Related
I was playing around with an example from the Isabelle/HOL tutorial to get a better understanding on the correspondence between Isar and Tactics proofs.
This is a version which works:
lemma rtrancl_converseD: "(x,y) ∈ (r ^-1 )^* ⟹ (y,x) ∈ r^* "
proof (induct y rule: rtrancl_induct)
case base
then show ?case ..
next case (step y z)
then have "(z, y) ∈ r" using rtrancl_converseD by simp
with `(y,x)∈ r^*` show "(z,x) ∈ r^*" using [[unify_trace_failure]]
apply (subgoal_tac "1=(1::nat)")
apply (rule converse_rtrancl_into_rtrancl)
apply simp_all
done
qed
I want to instantiate converse_rtrancl_into_rtrancl which proofs (?a, ?b) ∈ ?r ⟹ (?b, ?c) ∈ ?r^* ⟹ (?a, ?c) ∈ ?r^* .
But without the seemingly nonsensical apply (subgoal_tac "1=(1::nat)") line this errors with
Clash: r =/= Transitive_Closure.rtrancl
Failed to apply proof method⌂:
using this:
(y, x) ∈ r^*
(z, y) ∈ r
goal (1 subgoal):
1. (z, x) ∈ r^*
If I fully instantiate the rule apply (rule converse_rtrancl_into_rtrancl[of z y r x]) this becomes Clash: z__ =/= ya__.
This leaves me with three questions: Why does this specific case break? How can I fix it? And how can I figure out what went wrong in these cases since I can't really understand what the unify_trace_failure message wants to tell me.
rule-tactics are usually sensitive to the order of premises. The order of premises in converse_rtrancl_into_rtrancl and in your proof state don't match. Switching the order of premises in the proof state using rotate_tac will make them match the rule, so that you can directly apply fact like this:
... show "(z,x) ∈ r^*"
apply (rotate_tac)
apply (fact converse_rtrancl_into_rtrancl)
done
Or, if you want to include some kind of rule tactic, this would look like this:
apply (rotate_tac)
apply (erule converse_rtrancl_into_rtrancl)
apply (assumption)
(I personally don't use apply scripts ever in my everyday work. So apply-style gurus might know more elegant ways of handling this kind of situation. ;) )
Regarding your 1=(1::nat) / simp_all fix:
The whole goal can directly be solved by simp_all. So, attempts with adding stuff like 1=1 probably did not really tell you a lot about how much the other methods contributed to solving the proof.
However, the additional assumption seems to actually help Isabelle match converse_rtrancl_into_rtrancl correctly. (Don't ask me why!) So, one could indeed circumvent the problem by adding this spurious assumption and then eliminating it with refl again like:
apply (subgoal_tac "1=(1::nat)")
apply (erule converse_rtrancl_into_rtrancl)
apply (assumption)
apply (rule refl)
This does not look particularly elegant, of course.
The [[unify_trace_failure]] probably only really helps if one is familiar with the internal workings of Nipkow's higher-order unification algorithm. (I'm not.) I think the hint for the future here would really be that one must look closely at the order of premises for some tactics (rather than at the unifier debug output).
I found an explanation in the Isar reference 6.4.3 .
The with b1..bn command is equivalent to from b1..bn and this, i.e. it enters the proof chaining mode which adds them as (structured) assumptions to proof methods.
Basic proof methods (such as rule) expect multiple facts to be given
in their proper order, corresponding to a prefix of the premises of
the rule involved. Note that positions may be easily skipped using
something like from _ and a and b, for example. This involves the
trivial rule PROP ψ =⇒ PROP ψ, which is bound in Isabelle/Pure as “_”
(underscore).
Automated methods (such as simp or auto) just insert any given facts
before their usual operation. Depending on the kind of procedure
involved, the order of facts is less significant here.
Given the information about the 'with' translation and that rule expects chained facts in order, we could try to flip the chained facts. And indeed this works:
from this and `(y,x)∈ r^*` show "(z,x) ∈ r^*"
by (rule converse_rtrancl_into_rtrancl)
I think "6.4.3 Fundamental methods and attributes" is also relevant because it describes how the basic methods interact with incoming facts. Notably, the '-' noop which is sometimes used when starting proofs turns forward chaining into assumptions on the goal.
with `(y,x)∈ r^*` show "(z,x) ∈ r^*"
apply -
apply (rule converse_rtrancl_into_rtrancl; assumption)
done
This works because the first apply consumes all chained facts so the second apply is pure backwards chaining. This is also why the subgoal_tac or rotate_tac worked, but only if they are in seperate apply commands.
What is the correct way in Isabelle/HOL (2021) to define a function f from a specific set A to another set B?
From mathematics, a function f: A -> B is often defined as a map from its domain A to its co-domain B. And a function f is defined as a special kind of relation in A × B with only one y ∈ B that satisfies x f y for each x ∈ A.
But in Isabelle/HOL, functions seems to be defined in terms of computation, e.g. f x = Suc x. It seems that there is no place to define domain and co-domains explicitly.
I was just wondering if there is a conventional way to define functions in Isabelle to be with domain and co-domains and be compatible with the definition of relations above.
Background
As you have noted, in Isabelle/HOL, conventionally, a function is a term of the type 'a⇒'b, where 'a and 'b can be arbitrary types. As such, all functions in Isabelle are total. There is a blog post by Joachim Breitner that explains this very well: link. I will not restate any elements of the content of the blog post: instead, I will concentrate on the issue that you have raised in your question.
Conventional definitions of a function
I am aware of two methodologies for the definition of a function in traditional mathematics (here I use the term "traditional mathematics" to mean mathematics exposed in some set-theoretic foundation):
According, for example, to [1,Chapter 6], a function is simply a single-valued binary relation.
Some authors [2,Chapter 2] identify a function with its domain and codomain by definition, i.e. a function becomes a triple (A,B,r), where r⊆A×B is still a single-valued binary relation and A is exactly the domain of the relation.
You can find some further discussion here. If the function is a binary relation, then the domain and the range are normally identified with the domain and the range of the relation that the function represents. However, it makes little sense to speak about the codomain of such an entity. If the function is defined as a triple (A,B,r), then the codomain is the assigned set B.
Isabelle/HOL I: functions as relations
Isabelle/HOL already provides a definition of the concept of a single-valued relation in the theory Relation.thy. The definition is implicit in the definition of the predicate single_valued:
definition single_valued :: "('a × 'b) set ⇒ bool"
where "single_valued r ⟷ (∀x y. (x, y) ∈ r ⟶ (∀z. (x, z) ∈ r ⟶ y = z))"
Thus, effectively, a single-valued relation is a term of the type ('a × 'b) set such that it satisfies the predicate single_valued. Some elementary results about this definition are also provided.
Of course, this predicate can be used to create a new type constructor of "functions-as-relations" from 'a to 'b. See the official documentation of Isabelle [3, section 11.7] and the article Lifting and Transfer: A Modular Design for Quotients in Isabelle/HOL [4, section 3] for further information about defining new type constructors in Isabelle/HOL. It is not unlikely that such a type is already available somewhere, but I could not find it (or anything similar) after a quick search of the sources.
Of course, there is little that can prevent one from providing a type that captures either of the set-theoretic definitions of a function presented in the previous subsection of the answer. I guess, something like the following definition could work, but I have not tested it:
typedef ('a, 'b) relfun =
‹
{
(A::'a set, B::'b set, f::('a × 'b) set).
single_valued f ∧ Domain f = A ∧ Range f ⊆ B
}
›
proof-
let ?r = ‹({}, {}, {})›
show ?thesis unfolding single_valued_def by (intro exI[of _ ?r]) simp
qed
Isabelle/HOL II: FuncSet and other restrictions
While the functions in Isabelle/HOL are total, one can still mimick the restriction of a function to a certain pre-defined domain (i.e. a proper subset of UNIV::'a set) using a variety of methodologies. One common methodology (exposed in the theory HOL-Library.FuncSet) is to force the function to be undefined on parts of the domain. My answer in the following thread explains this in more detail.
Isabelle/HOL III: HOL/ZF, ZFC in HOL and HOTG
This might be marginally off-topic. However, there exist extensions of Isabelle/HOL with the axioms of set-theory of different strengths [5,6,7]. For example, ZFC in HOL [6] provides a certain type V that represents the von Neumann universe. One can now define all relevant set-theoretic concepts internalized in this type, including, of course, either one of the conventional definitions of a function. In ZFC in HOL one can internalize functions defined in HOL using the so-called operator VLambda like so: (F::V) = VLambda (A::V) (f::V⇒V). Now, F is a single-valued binary relation internalized in the type V with the domain A and the values of the form ⟨x, f x⟩.
As a side note, I have exposed both definitions of a function as predicates on V explicitly while working on my own formalization of category theory: Category Theory for ZFC in HOL.
Summary
What is the correct way in Isabelle/HOL (2021) to define a function f
from a specific set A to another set B?
To answer your question directly, my opinion is that there is no single "correct way" to define a function from a specific set A to another set B. However, you have many options that you can explore: each of these options will have advantages and disadvantages that are specific to it.
References
Takeuti G, Zaring WM. Introduction to Axiomatic Set Theory. Heidelberg: Springer-Verlag; 1971.
Goldblatt R. Topoi: The Categorial Analysis of Logic. Mineola: Dover Publications; 2013.
Wenzel M. The Isabelle/Isar Reference Manual. 2019.
Huffman B, Kunčar O. Lifting and Transfer: A Modular Design for Quotients in Isabelle/HOL. In: Gonthier G, Norrish M, editors. Certified Programs and Proofs. Heidelberg: Springer; 2013. p. 131–46.
Obua S. Partizan Games in Isabelle/HOLZF. In: Barkaoui K, Cavalcanti A, Cerone A, editors. Theoretical Aspects of Computing - ICTAC 2006. Berlin: Springer; 2006. p. 272–86.
Paulson LC. Zermelo Fraenkel Set Theory in Higher-Order Logic. Archive of Formal Proofs. 2019.
Chen J, Kappelmann K, Krauss A. https://bitbucket.org/cezaryka/tyset/src [Internet]. HOTG. Available from: https://bitbucket.org/cezaryka/tyset/src.
I am trying to prove the following basic theorem about the existence of the inverse function of a bijective function (to learn theorem-proving with Isabelle/HOL):
For any set S and its identity map 1_S, α:S→T is bijective iff there
exists a map β: T→S such that βα=1_S and αβ=1_S.
Below is what I have so far after some attempts to define relevant things including functions and their inverses. But I am pretty stuck and couldn't make much progress due to my lack of understanding of Isabelle and/or Isar.
theory Test
imports Main
"HOL.Relation"
begin
lemma bij_iff_ex_identity : "bij_betw f A B ⟷ (∃ g. g∘f = restrict id B ∧ f∘g = restrict id A)"
unfolding bij_betw_def inj_on_def restrict_def iffI
proof
let ?g = "restrict (λ y. (if f x = y then x else undefined)) B"
assume "(∀x∈A. ∀y∈A. f x = f y ⟶ x = y)"
have "?g∘f = restrict id B"
proof
(* cannot prove this *)
end
In above, I try to give an explicit existential witness (i.e. the inverse function g of the original function f). I have several issues about the proof.
whether the concepts are defined right (functions, inverse functions etc.) in Isabelle terms.
how to expand the relevant definitions and then simplify them with function applications. I have followed some Isabelle (2021) examples/tutorials about both the apply-style simp, and structured style Isar proof but couldn't use the Isar proof fluently. Once I started the proof command, I don't know how to simp or move any further.
Isar has the new way of assumes ... shows ... for stating the theorem. Is there similar support for proving iff's (⟷) like the example above? Without it, there is no access to assms etc., and is it necessary to assume everything except the conclusion during the proof.
Can someone help explain how the above existential proof about inverse function can be accomplished?
lemma bij_iff_ex_identity : "bij_betw f A B ⟷ (∃ g. g∘f = restrict id B ∧ f∘g = restrict id A)"
I think this is not exactly what you want an I am doubtful that it is true. g∘f = restrict id B does not mean that g∘f and id are equal on B. It means that the total function g∘f (and there are only total functions in HOL) equals the total function restrict id B. The latter returns id x on x∈B and undefined otherwise. So to make this equality true, g needs to output undefined whenever the input of f is not in B. But how would g know that!
If you want to use restrict, you could write restrict (g∘f) B = restrict id B. But personally, I would rather go for the simpler (∀x∈B. (g∘f) x = x).
So the corrected theorem would be:
lemma bij_iff_ex_identity : "bij_betw f A B ⟷ (∃ g. (∀x∈A. (g∘f) x = x) ∧ (∀y∈B. (f∘g) y = y))"
(Which is still wrong, by the way, as quickcheck tells me in Isabelle/jEdit, see the output window. If A has one element and B is empty, f cannot be a bijection. So the theorem you are attempting is actually mathematically not true. I will not attempt to fix it, but just answer the remaining lines.
unfolding bij_betw_def inj_on_def restrict_def iffI
The iffI here has no effect. Unfolding can only apply theorems of the form A = B (unconditional rewriting rules). iffI is not of that form. (Use thm iffI to see.)
proof
Personally, I don't use the bare form proof but always proof - or proof (some method). Because proof just applies some default method (in this case, equivalent to (rule iffI), so I think it's better to make it explicit. proof - just starts the proof without applying an extra method.
let ?g = "restrict (λ y. (if f x = y then x else undefined)) B"
You have an unbound variable x here. (Note the background color in the IDE.) That is most likely not what you want. Formally, it is allowed, but x will be treated as if it was some arbitrary constant.
Generally, I don't think there is any way to define g in a simple way (i.e., only with quantifiers and function applications and if-then-else). I think the only way to define an inverse (even if you know it exists), is to use the THE operator, because you need to say something like g y is "the" x such that f x = y. (And then later in the proof you will run into a proof obligation that it indeed exists and that it is unique.) See the definition of inv_into in Hilbert_Choice.thy (except it uses SOME not THE). Maybe for starters, try to do the proof just using the existing inv_into constant.
assume "(∀x∈A. ∀y∈A. f x = f y ⟶ x = y)"
All assume commands must have assumptions exactly as the are in the proof goal. You can test whether you wrote it right by just temporarily writing the command show A for A (that's an unprovable goal that would, however, finish the proof, so it tricks Isabelle into checking if it would). If this command does not give an error, you got the assumes right. In your cases, you didn't, it should be (∀x∈A. ∀y∈A. f x = f y ⟶ x = y) ∧ f ' A = B. (' is the backtick symbol here. Markup doesn't let me write it.)
My recommendation: Try the proof with bij instead of bij_betw first. (One direction is in BNF_Fixpoint_Base.o_bij if you want to cheat.)
Once done, you can try to generalize.
I agree with the insightful remarks provided by Dominique Unruh. However, I would like to mention that a theorem that captures the idea underlying the theorem that you are trying to prove already exists in the source code of the main library of Isabelle/HOL. In fact, it exists in at least two different formats: let me name them the traditional Isabelle/HOL format and the canonical FuncSet format. For the former one, see the theorem bij_betw_iff_bijections:
"bij_betw f A B ⟷ (∃g. (∀x ∈ A. f x ∈ B ∧ g(f x) = x) ∧ (∀y ∈ B. g y ∈ A ∧ f(g y) = y))"
The situation is a little bit more complicated with FuncSet. There does not seem to exist a single theorem that captures the idea. However, together, the theorems bij_betwI, bij_betw_imp_funcset and inv_into_funcset are nearly equivalent to the theorem that you are trying to state. Let me provide a sketch of how one could express this theorem in a manner that would be considered reasonably canonical in the FuncSet sense (try to prove it yourself):
lemma bij_betw_iff:
shows "bij_betw f A B ⟷
(
∃g.
(∀x. x∈A ⟶ g (f x) = x) ∧
(∀y. y∈B ⟶ f (g y) = y) ∧
f ∈ A → B ∧
g ∈ B → A
)"
sorry
I would also like to repeat the advice given by Dominique Unruh and provide several side remarks:
My recommendation: Try the proof with bij instead of bij_betw first.
Indeed, this is a very good idea. In general, by trying to restrict the problem to explicitly defined sets A and B, instead of working directly with types, you touched upon a topic that is known as relativization in logic. For a mild layman's introduction see, for example, https://leanprover.github.io/logic_and_proof/first_order_logic.html [1], for a slightly more thorough introduction in the context of set theory see [2, chapter 12]. As you have probably noticed by now, it is not that easy to relativize theorems in Isabelle/HOL and requires additional proof effort.
However, there exists an extension of Isabelle/HOL that allows for the automation of the process of the relativization of theorems. For more information about this extension see the article From Types to Sets by Local Type Definition in Higher-Order Logic by Ondřej Kunčar and Andrei Popescu [3]. There also exists a large scale application example of the framework [4]. Independently, I am working on making this extension more user-friendly and very slowly approaching the final stages in my efforts: see https://gitlab.com/user9716869/tts_extension. Thus, in principle, if you know how to use Types-To-Sets and you accept its axioms, then it is sufficient to prove the theorem with bij, e.g.,
"bij f ⟷ (∃g. (∀x. g (f x) = x) ∧ (∀y. f (g y) = y))",
Then, the theorems like
bij_betw_iff_bijections and bij_betw_iff can be synthesized automatically for free upon a click of a button (almost...).
Finally, for completeness, let me offer my own advice with regard to your queries (although, as I mentioned, I agree with everything stated by Dominique Unruh)
how to expand the relevant definitions and then simplify them with
function applications. I have followed some Isabelle (2021)
examples/tutorials about both the apply-style simp, and structured
style Isar proof but couldn't use the Isar proof fluently. Once I
started the proof command, I don't know how to simp or move any
further.
I believe that the best way to learn what you are trying to learn is by following through the exercises in the book Concrete Semantics by Tobias Nipkow and Gerwin Klein [5]. Additionally, I would also look through A Proof Assistant for Higher-Order Logic by Tobias Nipkow et al [6](it is slightly outdated, but I found it to be useful specifically for learning apply-style scripting/direct rule application). By the way, I have mostly self-taught myself Isabelle from these books without any prior experience in formal methods.
Isar has the new way of assumes ... shows ... for stating the theorem.
Is there similar support for proving iff's (⟷) like the example above?
Without it, there is no access to assms etc., and is it necessary to
assume everything except the conclusion during the proof.
I will make the advice given by Dominique Unruh more explicit: use rule iffI or intro iffI for this.
Edit. When you use rule iffI (or similar) to start your structured Isar proof, you need to state your assumptions explicitly for every subgoal (using the assume ... show ... paradigm). However, there is a tool that can generate such boilerplate Isar code automatically. It is called Sketch-and-Explore and you can find it in the directory HOL/ex of the main library of Isabelle/HOL. In this case, all you need to do is to type sketch(rule iffI) and the assume/show paradigm will be generated automatically for every subgoal.
References
Avigad J, Lewis RY, and van Doorn F. Logic and Proof.
Jech T. Set theory. 3rd ed. Heidelberg: Springer; 2006. (Pure and applied mathematics, a series of monographs and textbooks).
Kunčar O, Popescu A. From Types to Sets by Local Type Definition in Higher-Order Logic. Journal of Automated Reasoning. 2019;62(2):237–60.
Immler F, Zhan B. Smooth Manifolds and Types to Sets for Linear Algebra in Isabelle/HOL. In: 8th ACM SIGPLAN International Conference on Certified Programs and Proofs. New York: ACM; 2019. p. 65–77. (CPP 2019).
Nipkow T, Klein G. Concrete Semantics with Isabelle/HOL. Heidelberg: Springer-Verlag; 2017. (http://concrete-semantics.org/)
Nipkow T, Paulson LC, Wenzel M. A Proof Assistant for Higher-Order Logic. Heidelberg: Springer-Verlag; 2017.
I want to define "big" natural numbers as those larger than 10, and "small" ones as those less than 5. I can express these definition as locales:
locale Big =
fixes k :: ‹nat›
assumes ‹k > 10›
locale Small =
fixes k :: ‹nat›
assumes ‹k < 5›
I can then prove that 11 is a Big number and 2 is a Small one:
interpretation Big ‹11 :: nat› by (unfold_locales, simp)
interpretation Small ‹2 :: nat› by (unfold_locales, simp)
But how would I express and prove that 7 is not Small? I can prove that it is not less than 5, but the proof is unsatisfactory since it does not refer to the locale Small at all:
lemma ‹¬ ((7 :: nat) < (5 :: nat))› by simp
Moreover, how would I express that no integer exists which is both Big and Small? Again, I can prove it, but only without reference to the locales:
lemma
fixes k :: nat
shows ‹¬ (k < 5 ∧ k > 10)›
by simp
In general, how do I prove that something is not an interpretation of one or more locales? Or am I misusing the locale mechanism?
The command locale is documented in Isar-ref and the document "Tutorial to Locales and Locale Interpretation". Also, there has been a number of relevant publications that describe the implementation/syntax in more detail and in a more formal manner. One document that comes to my mind is Locales and Locale Expressions in Isabelle/Isar by Clemens Ballarin. It is outdated, but (in my view) it provides more elaborate explanation of the fundamental concepts than Isar-ref and the tutorial. In particular, see section 3.3: "Locale Predicates and the Internal Representation of Locales" in the aforementioned document.
But how would I express and prove that 7 is not Small? I can prove
that it is not less than 5, but the proof is unsatisfactory since it
does not refer to the locale Small at all:
Using the locale predicates, you may state the theorem in your question as follows:
lemma "¬Small 7" unfolding Small_def by auto
Whether or not using a locale predicate explicitly is sensible and whether there exist better options for expressing a given idea depends on the context.
Moreover, how would I express that no integer exists which is both Big
and Small?
lemma "¬(Small x ∧ Big x)" unfolding Small_def Big_def by simp
The main conclusion from the above is that locale predicates (e.g. Small) are merely constants and the command locale provides several theorems about these constants, including their definition (e.g. Small_def). The referenced documents provide further details.
In general, how do I prove that something is not an interpretation of
one or more locales? Or am I misusing the locale mechanism?
Unfortunately, in my view, these questions require clarification. Overall, the decision whether a locale, a class or a plain definition should be used to define a given concept depends on the application and, to a degree, on personal preferences.
I have seen a lot of documentation about Isabelle's syntax and proof strategies. However, little have I found about its foundations. I have a few questions that I would be very grateful if someone could take the time to answer:
Why doesn't Isabelle/HOL admit functions that do not terminate? Many other languages such as Haskell do admit non-terminating functions.
What symbols are part of Isabelle's meta-language? I read that there are symbols in the meta-language for Universal Quantification (/\) and for implication (==>). However, these symbols have their counterpart in the object-level language (∀ and -->). I understand that --> is an object-level function of type bool => bool => bool. However, how are ∀ and ∃ defined? Are they object-level Boolean functions? If so, they are not computable (considering infinite domains). I noticed that I am able to write Boolean functions in therms of ∀ and ∃, but they are not computable. So what are ∀ and ∃? Are they part of the object-level? If so, how are they defined?
Are Isabelle theorems just Boolean expressions? Then Booleans are part of the meta-language?
As far as I know, Isabelle is a strict programming language. How can I use infinite objects? Let's say, infinite lists. Is it possible in Isabelle/HOL?
Sorry if these questions are very basic. I do not seem to find a good tutorial on Isabelle's meta-theory. I would love if someone could recommend me a good tutorial on these topics.
Thank you very much.
You can define non-terminating (i.e. partial) functions in Isabelle (cf. Function package manual (section 8)). However, partial functions are more difficult to reason about, because whenever you want to use its definition equations (the psimps rules, which replace the simps rules of a normal function), you have to show that the function terminates on that particular input first.
In general, things like non-definedness and non-termination are always problematic in a logic – consider, for instance, the function ‘definition’ f x = f x + 1. If we were to take this as an equation on ℤ (integers), we could subtract f x from both sides and get 0 = 1. In Haskell, this problem is ‘solved’ by saying that this is not an equation on ℤ, but rather on ℤ ∪ {⊥} (the integers plus bottom) and the non-terminating function f evaluates to ⊥, and ‘⊥ + 1 = ⊥’, so everything works out fine.
However, if every single expression in your logic could potentially evaluate to ⊥ instead of a ‘proper‘ value, reasoning in this logic will become very tedious. This is why Isabelle/HOL chooses to restrict itself to total functions; things like partiality have to be emulated with things like undefined (which is an arbitrary value that you know nothing about) or option types.
I'm not an expert on Isabelle/Pure (the meta logic), but the most important symbols are definitely
⋀ (the universal meta quantifier)
⟹ (meta implication)
≡ (meta equality)
&&& (meta conjunction, defined in terms of ⟹)
Pure.term, Pure.prop, Pure.type, Pure.dummy_pattern, Pure.sort_constraint, which fulfil certain internal functions that I don't know much about.
You can find some information on this in the Isabelle/Isar Reference Manual in section 2.1, and probably more elsewhere in the manual.
Everything else (that includes ∀ and ∃, which indeed operate on boolean expressions) is defined in the object logic (HOL, usually). You can find the definitions, of rather the axiomatisations, in ~~/src/HOL/HOL.thy (where ~~ denotes the Isabelle root directory):
All_def: "All P ≡ (P = (λx. True))"
Ex_def: "Ex P ≡ ∀Q. (∀x. P x ⟶ Q) ⟶ Q"
Also note that many, if not most Isabelle functions are typically not computable. Isabelle is not a programming language, although it does have a code generator that allows exporting Isabelle functions as code to programming languages as long as you can give code equations for all the functions involved.
3)
Isabelle theorems are a complex datatype (cf. ~~/src/Pure/thm.ML) containing a lot of information, but the most important part, of course, is the proposition. A proposition is something from Isabelle/Pure, which in fact only has propositions and functions. (and itself and dummy, but you can ignore those).
Propositions are not booleans – in fact, there isn't even a way to state that a proposition does not hold in Isabelle/Pure.
HOL then defines (or rather axiomatises) booleans and also axiomatises a coercion from booleans to propositions: Trueprop :: bool ⇒ prop
Isabelle is not a programming language, and apart from that, totality does not mean you have to restrict yourself to finite structures. Even in a total programming language, you can have infinite lists. (cf. Idris's codata)
Isabelle is a theorem prover, and logically, infinite objects can be treated by axiomatising them and then reasoning about them using the axioms and rules that you have.
For instance, HOL assumes the existence of an infinite type and defines the natural numbers on that. That already gives you access to functions nat ⇒ 'a, which are essentially infinite lists.
You can also define infinite lists and other infinite data structures as codatatypes with the (co-)datatype package, which is based on bounded natural functors.
Let me add some points to two of your questions.
1) Why doesn't Isabelle/HOL admit functions that do not terminate? Many other languages such as Haskell do admit non-terminating functions.
In short: Isabelle/HOL does not require termination, but totality (i.e., there is a specific result for each input to the function) of functions. Totality does not mean that a function is actually terminating when transcribed to a (functional) programming language or even that it is computable at all.
Therefore, talking about termination is somewhat misleading, even though it is encouraged by the fact that Isabelle/HOL's function package uses the keyword termination for proving some property P about which I will have to say a little more below.
On the one hand the term "termination" might sound more intuitive to a wider audience. On the other hand, a more precise description of P would be well-foundedness of the function's call graph.
Don't get me wrong, termination is not really a bad name for the property P, it is even justified by the fact that many techniques that are implemented in the function package are very close to termination techniques from term rewriting or functional programming (like the size-change principle, dependency pairs, lexicographic orders, etc.).
I'm just saying that it can be misleading. The answer to why that is the case also touches on question 4 of the OP.
4) As far as I know Isabelle is a strict programming language. How can I use infinite objects? Let's say, infinite lists. Is it possible in Isabelle/HOL?
Isabelle/HOL is not a programming language and it specifically does not have any evaluation strategy (we could alternatively say: it has any evaluation strategy you like).
And here is why the word termination is misleading (drum roll): if there is no evaluation strategy and we have termination of a function f, people might expect f to terminate independent of the used strategy. But this is not the case. A termination proof of a function rather ensures that f is well-defined. Even if f is computable a proof of P merely ensures that there is an evaluation strategy for which f terminates.
(As an aside: what I call "strategy" here, is typically influenced by so called cong-rules (i.e., congruence rules) in Isabelle/HOL.)
As an example, it is trivial to prove that the function (see Section 10.1 Congruence rules and evaluation order in the documentation of the function package):
fun f' :: "nat ⇒ bool"
where
"f' n ⟷ f' (n - 1) ∨ n = 0"
terminates (in the sense defined by termination) after adding the cong-rule:
lemma [fundef_cong]:
"Q = Q' ⟹ (¬ Q' ⟹ P = P') ⟹ (P ∨ Q) = (P' ∨ Q')"
by auto
Which essentially states that logical-or should be "evaluated" from right to left. However, if you write the same function e.g. in OCaml it causes a stack overflow ...
EDIT: this answer is not really correct, check out Lars' comment below.
Unfortunately I don't have enough reputation to post this as a comment, so here is my go at an answer (please bear in mind I am no expert in Isabelle, but I also had similar questions once):
1) The idea is to prove statements about the defined functions. I am not sure how familiar you are with Computability Theory, but think about the Halting Problem and the fact most undeciability problems stem from it (such as Acceptance Problem). Imagine defining a function which you can't prove it terminates. How could you then still prove it returns the number 42 when given input "ABC" and it doesn't go in an infinite loop?
If instead you limit yourself to terminating functions, you can prove much more about them, essentially making a trade-off (or at least this is how I see it).
These ideas stem from Constructivism and Intuitionism and I recommend you check out Robert Harper's very interesting lecture series: https://www.youtube.com/watch?v=9SnefrwBIDc&list=PLGCr8P_YncjXRzdGq2SjKv5F2J8HUFeqN on Type Theory
You should check out especially the part about the absence of the Law of Excluded middle: http://youtu.be/3JHTb6b1to8?t=15m34s
2) See Manuel's answer.
3,4) Again see Manuel's answer keeping in mind Intuitionistic logic: "the fundamental entity is not the boolean, but rather the proof that something is true".
For me it took a long time to get adjusted to this way of thinking and I'm still not sure I understand it. I think the key though is to understand it is a more-or-less completely different way of thinking.