Some induction rules have case names: the default one has case 0 and case (Suc n) for example. Given a rule, e.g. int_induct, how do I find out its case names (if, indeed, it has these) without looking in the theory containing this lemma?
I'm not aware of any high-level way to do this. The case names are stored in the tags of a theorem that can be obtained with ML:
ML‹Thm.get_tags #{thm nat.induct}›
This prints:
val it = [("name", "Nat.nat.induct"), ("kind", "theorem"), ("case_names", "zero;Suc")]: Properties.T
As you can see, the case names are available under the key case_names.
Related
I generate lists with various integer patterns and I'd like to prove that the generated lists hold certain properties. The lemmas refer to the items of the generated lists by their positions. The generator functions receive the desired list length as parameter. Working with induction, the length of the list must be constrained as being greater or equal to 0, so that the positional references are valid, which yields a base induction caselike this:
0 < 0 ... ==> Property(generator(0))
which holds and disappears after apply(simp) but seems to be irrelevant.
Would it still be a valid proof provided that the induction step holds too? Is there a better approach?
Yes, the proof is still valid. It's perfectly fine that sometimes in induction proofs some cases are vacuous.
Is there a convergence theory in Isabelle/HOL? I need to define ∥x(t)∥ ⟶ 0 as t ⟶ ∞.
Also, I'm looking for vectors theory, I found a matrix theory but I couldn't find the vectors one, Is there exist such theory in Isabelle/HOL?
Cheers.
Convergence etc. are expressed with filters in Isabelle. (See the corresponding documentation)
In your case, that would be something like
filterlim (λt. norm (x t)) (nhds 0) at_top
or, using the tendsto abbreviation,
((λt. norm (x t)) ⤏ 0) at_top
where ⤏ is the Isabelle symbol \<longlongrightarrow>, which can be input using the abbreviation --->.
As a side note, I am wondering why you are writing it that way in the first place, seeing as it is equivalent to
filterlim x (nhds 0) at_top
or, with the tendsto syntax:
(x ⤏ 0) at_top
Reasoning with these filters can be tricky at first, but it has the advantage of providing a unified framework for limits and other topological concepts, and once you get the hang of it, it is very elegant.
As for vectors, just import ~~/src/HOL/Analysis/Analysis. That should have everything you need. Ideally, build the HOL-Analysis session image by starting Isabelle/jEdit with isabelle jedit -l HOL-Analysis. Then you won't have to process all of Isabelle's analysis library every time you start the system.
I assume that by ‘vectors’ you mean concrete finite-dimensional real vector spaces like ℝn. This is provided by ~~/src/HOL/Analysis/Finite_Cartesian_Product.thy, which is part of HOL-Analysis. This provides the vec type, which takes two parameters: the component type (probably real in your case) and the index type, which specifies the dimension of the vector space.
There is also a pre-defined type n for every positive integer n, so that you can write e.g. (real, 3) vec for the vector space ℝ³. There is also type syntax so that you can write 'a ^ 'n for ('a, 'n) vec.
When I use value to find out some value of a function that returns natural numbers, I always obtain the answer in the form of iterated Successor functions of 0, i.e., Suc(Suc( ... 0 )) which can be hard to read sometimes.
Is there a way to output directly the number that Isabelle returns?
This is something I wanted to fix some time ago but apparently I forgot. Carcigenate's guess is incorrect; this is indeed the fully evaluated result. The problem is just that natural numbers are printed in this unwieldy way.
You can do the following things:
The easiest way is to convert the number to an integer, i.e. instead of value "foo x y z" (where foo x y z is the expression of type nat that you want to eavluate) you write value "int (foo x y z)".
You can add ~~/src/HOL/Library/Code_Target_Numeral to your imports. This makes Isabelle's code generator use arbitrary-precision integers of the target language (in case of value, that's ML and its GMP-based integers) instead of the inefficient successor notation. As a side effect, this also prints natural numbers in a nicer way.
You can add the following code to your theory, which changes the way the value command displays natural numbers:
Code:
lemma Suc_numeral_bit0: "Suc (numeral (Num.Bit0 n)) = numeral (Num.Bit1 n)"
by (subst Suc_numeral) simp
lemma Suc_numeral_bit1: "Suc (numeral (Num.Bit1 n)) = numeral (Num.Bit0 (n + Num.One))"
by (subst Suc_numeral) simp
lemmas [code_post] =
One_nat_def [symmetric] Suc_numeral_bit0 Suc_numeral_bit1 Num.Suc_1 Num.arith_simps
Note that the value command is a diagnostic command only. It is mainly used for quick plausibility tests and debugging of code generation setups, and getting it to work can sometimes be tricky.
By default, value relies on the code generator, i.e. Isabelle needs to know how to generate executable code for the expression, and if it cannot do that, value will probably fail. (It can sometimes also fall back to some other strategies, normalisation by evaluation or evaluation by simplification, but those usually don't provide useful output)
I'm just telling you this so that you know what to expect from the value command and don't get the impression that this is some integral part of Isabelle that people use all the time.
I want to find theorems. I have read the section on find_theorems in the Isabelle/Isar reference manual:
find_theorems criteria
Retrieves facts from the theory or proof context matching all of given search
criteria. The criterion name: p selects all theorems whose fully qualified
name matches pattern p, which may contain "*" wildcards. The criteria intro,
elim, and dest select theorems that match the current goal as introduction,
elimination or destruction rules, respectively. The criterion solves returns
all rules that would directly solve the current goal. The criterion simp: t
selects all rewrite rules whose left-hand side matches the given term. The
criterion term t selects all theorems that contain the pattern t -- as usual,
patterns may contain occurrences of the dummy "_" , schematic variables, and
type constraints.
Criteria can be preceded by "-" to select theorems that do not match. Note
that giving the empty list of criteria yields all currently known facts. An
optional limit for the number of printed facts may be given; the default is 40.
By default, duplicates are removed from the search result. Use with_dups to
display duplicates.
As far as I understand, find_theorems is used in the find window of Isabelle/jEdit. The above does not help me finding relevant theorems for the following situation (Lambda is a theory of the Nominal Isabelle extension. The tarball is here):
theory First
imports Lambda
begin
theorem "Lam [x].(Lam [y].(App (Var x)(Var y))) = Lam [y].(Lam [x].(App (Var y)(Var x)))"
When I try the search expression Lam Isabelle/jedit says
Inner syntax error: unexpected end of input
Failed to parse term
How can I make it look for all the theorems that contain the constant Lam?
Since Lam like the ordinary lambda (%) is not a term on its own, you should add the remaining parts to get a proper term, which may contain wildcards. In your example, I would perform
find_theorems "Lam [_]. _"
which gives lots of answers.
Typically this happens whenever special syntax was defined for some constant. But there is (almost) always an underlying ("raw") constant. To find out which constant provides the Lam [_]. _ syntax. You can Ctrl-click Lam (inside a proper term) within Isabelle/jEdit. This will jump to the definition of the underlying constant.
For Lam there is the additional complication that the binder syntax uses exactly the same string as the underlying constant, namely Lam, as can be seen at the place of definition:
nominal_datatype lam =
Var "name"
| App "lam" "lam"
| Lam x::"name" l::"lam" binds x in l ("Lam [_]. _" [100, 100] 100)
In such cases you can use the long name of the constant by prefixing it with the theory name, i.e., Lambda.Lam.
Note: The same works for binders like ALL x. P x (with underlying constant All), but not for the built-in %x. x.
Is it possible to give my own names to the variables generated when using case analysis or induction?
If you are using structured proofs (starting with the proof keyword), you can use the case keywoard to select the case you want to prove and give names to the variables created by case analysis / induction:
lemma "length (rev xs) = length xs"
proof (induct xs)
case Nil
then show ?case ...
next
case (Cons x xs)
then show ?case ...
qed
Here case (Cons x xs) tells Isabelle that you want to prove the case where a list consists of a start element and a remaining list (i.e., the induction step) and name the variables x and xs.
In the proof block, you can see the list of cases with the print_cases command.
If on the other hand you are using apply-style, there is no direct way to name these variables (also, in this case you are likely to need case_tac instead of cases, as you will have to deal with bound variables instead of free variables). There is the method rename_tac which can be used to rename the outermost meta-quantified variables.
For most projects (with the notable exception of program verification, like in the L4.verified project), the common proof style is to use mostly structured proofs. Unstructured proofs are used for exploration and become seldom so complex that it is necessary to rename your variables.