Accessing first element of a matrix in Isabelle - matrix

Accessing the “first” element of a matrix
I want to write a proof about a trivial case of the determinant of a matrix, where the matrix consists of just a single element (i.e., the cardinality of 'n is one).
Thus the determinant (or det A) is the single element in the matrix.
However, it is not clear to me how to reference the single element of the matrix. I tried A $ zero $ zero, which did not work.
My current way to demonstrate the problem is to write ∀a∈(UNIV :: 'n set). det A = A $ a $ a. It assumes that the cardinality of the numeral type is one.
What is the correct way to write this trivial proof about determinants?
Here is my current code:
theory Notepad
imports
Main
"~~/src/HOL/Library/Polynomial"
"~~/src/HOL/Algebra/Ring"
"~~/src/HOL/Library/Numeral_Type"
"~~/src/HOL/Library/Permutations"
"~~/src/HOL/Multivariate_Analysis/Determinants"
"~~/src/HOL/Multivariate_Analysis/L2_Norm"
"~~/src/HOL/Library/Numeral_Type"
begin
lemma det_one_element_matrix:
fixes A :: "('a::comm_ring_1)^'n∷finite^'n∷finite"
assumes "card(UNIV :: 'n set) = 1"
shows "∀a∈(UNIV :: 'n set). det A = A $ a $ a"
proof-
(*sledgehammer proof of 1, 2 and ?thesis *)
have 1: "∀a∈(UNIV :: 'n set). UNIV = {a}"
by (metis (full_types) Set.set_insert UNIV_I assms card_1_exists ex_in_conv)
have 2:
"det A = (∏i∈UNIV. A $ i $ i)"
by (metis (mono_tags, lifting) "1" UNIV_I det_diagonal singletonD)
from 1 2 show ?thesis by (metis setprod_singleton)
qed
UPDATE:
Unfortunately, this is part of a larger theorem which is already proven for the cardinality of 'n∷finite > 1. In this theorem the type of matrix A is
fixed as A :: "('a::comm_ring_1)^'n∷finite^'n∷finite and the definition of the determinant is used in this larger theorem.
Therefore, I don't think I can change the type of my matrix A to ('a::comm_ring_1)^1^1) in oder to solve my larger theorem.

I feel that my previous answer is the better solution in general if it is possible to use, so I will leave it as-is. In your case where you are not able to use this approach, things get a little harder, unfortunately.
What you need to show is that:
There can only be a single element in your type 'n, and thus every element is equal;
Additionally, the definition of det also references permutations, so we need to show that there only exists a single function of type 'n ⇒ 'n, which happens to be equal to the function id.
With these in place, we can carry out the proof as follows:
lemma det_one_element_matrix:
fixes A :: "('a::comm_ring_1)^'n∷finite^'n∷finite"
assumes "card(UNIV :: 'n set) = 1"
shows "det A = A $ x $ x"
proof-
have 0: "⋀x y. (x :: 'n) = y"
by (metis (full_types) UNIV_I assms card_1_exists)
hence 1: "(UNIV :: 'n set) = {x}"
by auto
have 2: "(UNIV :: ('n ⇒ 'n) set) = {id}"
by (auto intro!: ext simp: 0)
thus ?thesis
by (auto simp: det_def permutes_def 0 1 2 sign_id)
qed

Using A $ zero $ zero (or A $ 0 $ 0) wouldn't have worked, because the vectors are indexed from 1: A $ 0 $ 0 is undefined, which makes it hard to prove anything about.
Playing a little myself, I came up with the following lemma:
lemma det_one_element_matrix:
"det (A :: ('a::comm_ring_1)^1^1) = A $ 1 $ 1"
by (clarsimp simp: det_def sign_def)
Instead of using a type 'a :: finite and assuming it has cardinality 1, I used the standard Isabelle 1 type which encodes both these facts into the type itself. (Similar types exist for all numerals, so you can write things like 'a ^ 23 ^ 72)
Incidentally, after typing in the lemma above, auto solve_direct quickly informed me that something already exists in the library stating the same result, a lemma named det_1.

Related

How can I subtract a multiset from a set with a given multiset?

So I'm trying to define a function apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset"
It takes in a function C that may convert an 'a multiset into a single element of type 'a. Here we assume that each element in the domain of C is pairwise mutually exclusive and not the empty multiset (I already have another function that checks these things). apply will also take another multiset inp. What I'd like the function to do is check if there is at least one element in the domain of C that is completely contained in inp. If this is the case, then perform a set difference inp - s where s is the element in the domain of C and add the element the (C s) into this resulting multiset. Afterwards, keep running the function until there are no more elements in the domain of C that are completely contained in the given inp multiset.
What I tried was the following:
fun apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset" where
"apply_C C inp = (if ∃s ∈ (domain C). s ⊆# inp then apply_C C (add_mset (the (C s)) (inp - s)) else inp)"
However, I get this error:
Variable "s" occurs on right hand side only:
⋀C inp s.
apply_C C inp =
(if ∃s∈domain C. s ⊆# inp
then apply_C C
(add_mset (the (C s)) (inp - s))
else inp)
I have been thinking about this problem for days now, and I haven't been able to find a way to implement this functionality in Isabelle. Could I please have some help?
After thinking more about it, I don't believe there is a simple solutions for that Isabelle.
Do you need that?
I have not said why you want that. Maybe you can reduce your assumptions? Do you really need a function to calculate the result?
How to express the definition?
I would use an inductive predicate that express one step of rewriting and prove that the solution is unique. Something along:
context
fixes C :: ‹'a multiset ⇒ 'a option›
begin
inductive apply_CI where
‹apply_CI (M + M') (add_mset (the (C M)) M')›
if ‹M ∈ dom C›
context
assumes
distinct: ‹⋀a b. a ∈ dom C ⟹ b ∈ dom C ⟹ a ≠ b ⟹ a ∩# b = {#}› and
strictly_smaller: ‹⋀a b. a ∈ dom C ⟹ size a > 1›
begin
lemma apply_CI_determ:
assumes
‹apply_CI⇧*⇧* M M⇩1› and
‹apply_CI⇧*⇧* M M⇩2› and
‹⋀M⇩3. ¬apply_CI M⇩1 M⇩3›
‹⋀M⇩3. ¬apply_CI M⇩2 M⇩3›
shows ‹M⇩1 = M⇩2›
sorry
lemma apply_CI_smaller:
‹apply_CI M M' ⟹ size M' ≤ size M›
apply (induction rule: apply_CI.induct)
subgoal for M M'
using strictly_smaller[of M]
by auto
done
lemma wf_apply_CI:
‹wf {(x, y). apply_CI y x}›
(*trivial but very annoying because not enough useful lemmas on wf*)
sorry
end
end
I have no clue how to prove apply_CI_determ (no idea if the conditions I wrote down are sufficient or not), but I did spend much thinking about it.
After that you can define your definitions with:
definition apply_C where
‹apply_C M = (SOME M'. apply_CI⇧*⇧* M M' ∧ (∀M⇩3. ¬apply_CI M' M⇩3))›
and prove the property in your definition.
How to execute it
I don't see how to write an executable function on multisets directly. The problem you face is that one step of apply_C is nondeterministic.
If you can use lists instead of multisets, you get an order on the elements for free and you can use subseqs that gives you all possible subsets. Rewrite using the first element in subseqs that is in the domain of C. Iterate as long as there is any possible rewriting.
Link that to the inductive predicate to prove termination and that it calculates the right thing.
Remark that in general you cannot extract a list out of a multiset, but it is possible to do so in some cases (e.g., if you have a linorder over 'a).

Expanding all definitions in Isabelle lemma

How can I tell Isabelle to expand all my definitions, please, because that way the proof is trivial? Unfortunately there is no default expansion or simplification happens, and basically I get back the original expression as the subgoal.
Example:
theory Test
imports Main
begin
definition b0 :: "nat⇒nat"
where "b0 n ≡ (n mod 2)"
definition b1 :: "nat⇒nat"
where "b1 n ≡ (n div 2)"
lemma "(a::nat)≤3 ∧ (b::nat)≤3 ⟶
2*(b1 a)+(b0 a)+2*(b1 b)+(b0 b) = a+b"
apply auto
oops
end
Respose before oops:
proof (prove)
goal (1 subgoal):
1. a ≤ 3 ⟹
b ≤ 3 ⟹ 2 * b1 a + b0 a + 2 * b1 b + b0 b = a + b
My recommendation: unfolding
There is a special keyword unfolding for unpacking definitions at the start of proofs. For your example this would read:
unfolding b0_def b1_def by simp
I consider unfolding the most elegant way. It also helps while writing the proofs. Internally, this is (mostly?) equivalent to using the unfold-method:
apply (unfold b0_def b1_def) by simp
This will recursively (!) use the set of equalities you supply to rewrite the proof goal. (Due to the recursion, you should rather not supply a set of equalities that could generate cycles...)
Alternative: Using the simplifier
In cases with possible loops, the simplifier might be able to reach a nice unfolding without running into these cycles, maybe by interleaving with other simplifications. In such cases, by (simp add: b0_def b1_def), as you've suggested, is great!
Alternative definition: Maybe it's just an abbreviation (and no definition)?
If you find yourself unfolding a definition in every single instance, you could consider, using abbreviation instead of definition. Then, some Isabelle magic will do the packing/unpacking for you without further hints. abbeviation does only affect how the user communicates with Isabelle. It does not introduce new symbols at the object level, and consequently, there would be no b1_def facts and the like.
abbreviation b0 :: "nat⇒nat"
where "b0 n ≡ (n mod 2)"
Usually not recommended: Building something like an abbreviation using the simplifier
If you (for whatever reason) want to have a defined name at the object level, but unfold it in almost every instance, you can also feed the defining equality directly into the simplifier.
definition b0 :: "nat⇒nat"
where [simp]: "b0 n ≡ (n mod 2)"
(Usually there should be little reason for the last option.)
Yes, I keep forgetting that definitions are not used in simplifications by default.
Adding the definitions explicitly to the simplification rules solves this problem:
lemma "(a::nat)≤3 ∧ (b::nat)≤3 ⟶
2*(b1 a)+(b0 a)+2*(b1 b)+(b0 b) = a+b"
by (simp add: b0_def b1_def)
This way the definitions (b0, b1) are correctly used.

Find the origin of "Ratio has zero denominator" Exception

As a personal excercize in the process of learning Haskell, I'm trying to port this F# snippet for Random Art.
I've not embedded full source code for not bloating the question, but is available as gist.
An important part of the program is this Expr type:
data Expr =
VariableX
| VariableY
| Constant
| Sum Expr Expr
| Product Expr Expr
| Mod Expr Expr
| Well Expr
| Tent Expr
| Sin Expr
| Level Expr Expr Expr
| Mix Expr Expr Expr
deriving Show
and two functions:
gen :: Int -> IO Expr random generates a tree-like structure given a number of iterations
eval :: Expr -> IO (Point -> Rgb Double) walks the tree and terminates producing a drawing function.
More high is the number passed to gen than higher are the probability that the following exception is generated: Ratio has zero denominator.
I'm new to Haskell so to solve the problem I've tried to compile it as above:
ghc RandomArt.hs -prof -auto-all -caf-all
Obtaining only this more (to me quite useless) info:
$ ./RandomArt +RTS -xc
*** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace:
GHC.Real.CAF
--> evaluated by: Main.eval.\,
called from Main.eval,
called from Main.tga.pxs',
called from Main.tga,
called from Main.save,
called from Main.main,
called from :Main.CAF:main
--> evaluated by: Main.eval.\.r,
called from Main.eval.\,
called from Main.eval,
called from Main.tga.pxs',
called from Main.tga,
called from Main.save,
called from Main.main,
called from :Main.CAF:main
*** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace:
Main.tga,
called from Main.save,
called from Main.main,
called from GHC.Real.CAF
RandomArt: Ratio has zero denominator
The code that persist the generated function to a TGA file works because it was my previous excercize (a port from OCaml).
I've tried executing various Expr tree from GHCi, assembling data by hand or applying functions as in the program but I wasn't able to identify the bug.
Haskell docs talks about a package named loch that should able to compile preserving source code line numbers, but I was not able to install it (while I normally install with cabal install every package I need).
The question, to be honest are two:
where's is the bug (in this specific case)?
which tool do I need to master to find bugs like this (or bugs in general)?
Thanks in advance.
The exception
Let's focus on the exception first.
Finding the bug
where's is the bug (in this specific case)?
In mod'. We can check this easily if we provide an alternative version instead of the one by Data.Fixed:
mod' :: RealFrac a => a -> a -> a
mod' _ 0 = error "Used mod' on 0"
mod' a b =
let k = floor $ a / b
in a - (fromInteger k) * b
We now get Used mod' on 0.
Rationale
which tool do I need to master to find bugs like this (or bugs in general)?
In this case, the necessary hint was already in the exception's message:
Ratio has zero denominator
This means that there's a place where you divide by zero in the context of a Ratio. So you need to look after all places where you divide something. Since you use only (/) and mod', it boils down to whether one of them actually can throw this exception:
(/) usually returns ±Infinity on division by zero if used on Double,
mod' uses toRational internally, which is a Ratio Integer.
So there's only one culprit left. Note that the other implementation yields the same results if b isn't zero.
The actual problem
Using mod or mod' with b == 0 isn't well-defined. After all, a modulo operation should hold the following property:
prop_mod :: Integral n => n -> n -> Bool
prop_mod a b =
let m = a `mod` b
d = a `div` b
in a == b * d + m -- (1)
&& abs m < abs b -- (2)
If b == 0, there doesn't exist any pair (d, m) such that (1) and (2) hold. If we relax this law and throw (2) away, the result of mod isn't necessarily unique anymore. This leads to the following definition:
mod' :: RealFrac a => a -> a -> a
mod' a 0 = a -- this is arbitrary
mod' a b =
let k = floor $ a / b
in a - (fromInteger k) * b
However, this is an arbitrary definition. You have to ask yourself, "What do I actually want to do if I cannot use mod in a sane way". Since F# apparently didn't complain about a % 0, have a look at their documentation.
Either way, you cannot use a library mod function, since they aren't defined for a zero denominator.

Create a quotient-lifted type with polymorphism over working set and equivalence relation in Isabelle/HOL

I would like to create a quotient type with quotient_type in Isabelle/HOL in which I would left "non-constructed" the non-empty set S and the equivalence relation ≡. The goal is for me to derive generic properties w.r.t. S and ≡ over the quotient-lifted set S/≡. In this way, it would be interesting that Isabelle/HOL accepts dependent types... But I was told that was not possible.
Hence, I tried this
(* 1. Defining an arbitrary set and its associated type *)
consts S :: "'a set"
typedef ('a) inst = "{ x :: 'a. ¬ S = ({} :: 'a set) ⟶ x ∈ S}" by(auto)
(* 2. Defining the equivalence relation *)
definition equiv :: "'a ⇒ 'a ⇒ bool" where
"equiv x y = undefined"
(* here needs a property of equivalence relationship... *)
(* 3. Defining the quotiented set *)
quotient_type ('a) quotiented_set = "('a inst × 'a inst)" / "equiv"
(* Hence, impossible end proof here... *)
Is this formalization, there appears to be two problems
I don't think this is the cleanest way to define an arbitrary set S as I can't specify it to be non-empty...
I can't define an arbitrary equivalence relation equiv with the definition nor the fun commands as they only allow me define "constructive-strongly normalizing-inductive" definitions only... And yet, I want to say that I just have some function equiv that satisfies properties of equivalence (reflexivity, symmetry, transitivity).
Do you have any idea ? Thanks.
HOL types cannot depend on values. So if you want to define a quotient type for an arbitrary non-empty set S and equivalence relation equiv using quotient_type, the arbitrary part must stay at the meta-level. Thus, S and equiv can either be axiomatized or defined such that you can convince yourself that you really have captured the desired notion of arbitrary.
If you axiomatize S and equiv, then you yourself are responsible that the axioms are consistent with the other axioms of HOL. You can do that with the command axiomatization as in
axiomatization S :: "'a set" where S_not_empty: "S ≠ {}"
For Isabelle/HOL, S is then a fixed constant of which you only know that it is not empty. You will never be able to instantiate S, because the arbitrariness only exists in the set-theoretic interpretation of Isabelle/HOL.
If you do not want to add new axioms, you can use specification instead:
consts S :: "'a set"
specification (S) S_not_empty: "S ≠ {}" by auto
With specification, you have to prove that your axioms are consistent, so there is no danger here. However, S no longer is absolutely arbitrary, because it is defined in terms of the choice operator Eps, as can be seen from the generated theorem S_def.
If you really want to study the theory of quotients within Isabelle/HOL, I recommend that you do not use types, but ordinary sets. There is the quotient operator op // and some theorems in the theory Equiv_Relations which is part of the library.

Isabelle: Issue with leibniz formula

As I understand it, matrices in Isabelle are essentially functions and of abitrary dimension. In this setting, it is not easy to define a squared matrix (n x n matrix). Also, in a proof on paper the dimension "n" of a squared can be used in the proof. But how do I do that in Isabelle?
Leibniz Formula:
My proof on paper:
Here is a relevant excerpt of my Isabelle proof:
(* tested with Isabelle2013-2 (and also Isabelle2013-1) *)
theory Notepad
imports
Main
"~~/src/HOL/Library/Polynomial"
"~~/src/HOL/Multivariate_Analysis/Determinants"
begin
notepad
begin
fix C :: "('a::comm_ring_1 poly)^'n∷finite^'n∷finite"
(* Definition Determinant (from the HOL Library, shown for reference
see: "~~/src/HOL/Multivariate_Analysis/Determinants") *)
have "det C =
setsum (λp. of_int (sign p) *
setprod (λi. C$i$p i) (UNIV :: 'n set))
{p. p permutes (UNIV :: 'n set)}" unfolding det_def by simp
(* assumtions *)
have 1: "∀ i j. degree (C $ i $ j) ≤ 1" sorry (* from assumtions, not shown *)
have 2: "∀ i. degree (C $ i $ i) = 1" sorry (* from assumtions, not shown *)
(* don't have "n", that is the dimension of the squared matrix *)
have "∀p∈{p. p permutes (UNIV :: 'n set)}. degree (setprod (λi. C$i$p i) (UNIV :: 'n set)) ≤ n" sorry (* no n! *)
end
What can I do in this situation?
UPDATE:
Your type for C, a restricted version of ('a ^ 'n ^ 'n), appears to be a custom type of > yours, because I get an error when trying to use it, even after importing > Polynomial.thy. But maybe it's defined in some other HOL theory.
Unfortunately I did not write the includes in my code example, please see the updated example. But it is not a custom type, importing "Polynomial.thy" and "Determinants" should be sufficient. (I tested Isabelle version 2013-1 and 2013-2.)
If you're using a custom definition of a matrix, there's a good chance
you're on your own, for the most part.
I don't belive I am using a custom definition of a matrix.
The library Determinants (~~/src/HOL/Multivariate_Analysis/Determinants) has the following definition of a determinant:
definition det:: "'a::comm_ring_1^'n^'n ⇒ 'a" where .... So the library uses the notion of a matrix as a vector of vectors. If my ring is over polynomials it should not make a difference in my eyes.
Regardless, for a type such as ('a ^ 'n ^ 'n), it seems to me, you
should be able to write a function to return a value for the size of
the matrix. So if (p ^ n ^ n) is a matrix, where n is a set, then
maybe the cardinality of n is the n you want in your question.
This brought me on the right way. My current guess is that the following definition is helpful:
definition card_diagonal :: "('a::zero poly)^'n^'n ⇒ nat" where "card_diagonal A = card { (A $ i $ i) | i . True }"
card is definied in Finite_Set.
It seems to me that the essence of this question is how to obtain the integer n from a given n x n matrix, A. The difficulty here is that this integer is encoded in A's type. Nevertheless, it seems clear to me that n is actually a parameter of the problem. Although we can imagine representations of matrices that somehow store the dimension internally, from a mathematical point of view, it is natural to begin the entire development by stating "let n be a positive integer".
Update 140107_2040
It's hard to make a short answer here. I only work everything for vectors, since it all gets very involved. I try to give you the function for the length of a vector as fast as possible. I then go into a big explanation on what I did to get a decent understanding of the vector type, but not necessarily for you, if you don't need it.
Reflected by the name Finite_Cartesian_Product.thy, Amine Chaieb defines a generalized finite Cartesian product. So, of course, we also get a definition for vectors and n-tuples. That it's a generalized Cartesian product is what requires the huge explanation, and what took me a long time to recognize and work through. Having said that, I'll call it a vector, since he named the type vec.
Everything needs to be understood in reference to what a vector is, which is defined by this definition:
typedef ('a, 'b) vec = "UNIV :: (('b::finite) => 'a) set"
This tells us that a vector is a function f::('b::finite) => 'a. The domain of the function is UNIV::'b set, which is finite and is called the index set. For example, let the index set be defined with typedef as {1,2,3}.
The codomain of the function can be any type, but let it be a set of constants {a,b}, defined with typedef. Because HOL functions are total, each element of {1,2,3} must get mapped to an element of {a,b}.
Now, consider the set of all such functions that map elements from {1,2,3} to {a,b}. There will be 2^3 = 8 such functions. I now resort to ZFC function notation, along with n-tuple notation:
f_1: {1,2,3} --> {a,b} == {(1,a),(2,a),(3,a)} == (a,a,a)
f_2 == {(1,a),(2,a),(3,b)} == (a,a,b)
f_3 == {(1,a),(2,b),(3,a)} == (a,b,a)
f_4 == {(1,a),(2,b),(3,b)} == (a,b,b)
f_5 to f_8 == (b,a,a), (b,a,b), (b,b,a), (b,b,b)
Then for any vector f_i, which, again, is a function, the length of the vector will be the cardinality of the domain of f_i, which will be 3.
I'm pretty sure your function card_diagonal is the cardinality of the range of the function, and I tested out a vector version of it much further down, but it basically showed me how to get the cardinality of the domain.
Here is the function for the length of a vector:
definition vec_length :: "('a, 'b::finite) vec => nat" where
"vec_length v = card {i. ? c. c = (vec_nth v) i}"
declare
vec_length_def [simp add]
You might want to substitute v $ i for (vec_nth v) i. The ? is \<exists>.
In my example below, the simp method easily produced a goal CARD(t123) = (3::nat), where t123 is a type I defined with 3 elements in it. I couldn't get past that.
Anyone who wants to understand the details needs to understand the use of the Rep_t and Abs_t functions that are created when typedef is used to create a type t. In the case of vec, the functions would have been Rep_vec and Abs_vec, but they are renamed with morphisms to vec_nth and vec_lambda.
Will the Non-vector-specific Vector Length Please Step Forward
Update 140111
This should be my final update, because to completely work it out to my satisfaction, I need to know much more about instantiating type classes in general, and how to specifically instantiate type classes so that my concrete example, UNIV::t123 set, is finite.
I more than welcome being corrected where I may be wrong. I would much rather be reading about Multivariate_Analysis in a textbook than be learning how to use Isar and Isabelle/HOL like this.
By all appearances, the concept of the length of a vector of type ('a, 'b) vec is extraordinarily simple. It is the cardinality of the universal set of the type 'b::finite.
Intuitively, it makes sense, so I commit to the idea prematurely, but I don't permanently commit because I can't finish my example.
I added an update to the end of my "investigative" theory below.
What I hadn't done before is instantiate my example type, t123, a type defined with the set {c1,c2,c3}, as type class top.
The shorter story is that in pursuing top, value tipped me off that type class card_UNIV is involved, where card_UNIV is based on finite_UNIV. Again, the descriptive identifiers make it seem that if my type t123 is of type class finite_UNIV, then I can calculate the cardinality of it with card, which will be the length of any vector using type t123 as the index set.
I show some terms here which indicate what's involved, which, as usual, can be investigated by cntl-clicking on various identifiers, if you have my example theory loaded. A little more detail is in my investigative source below.
term "UNIV::t123 set"
term "top::t123 set"
term "card (UNIV::t123 set)" (*OUTPUT PANEL: CARD(t123)::nat.*)
term "card (top::t123 set)" (*OUTPUT PANEL: CARD(t123)::nat.*)
value "card (top::t123 set)" (*ERROR: Type t123 not of sort card_UNIV.*)
term "card_UNIV"
term "finite_UNIV"
(End of update.)
140112 Final update to the final update
It paid to not permanently commit, and though answering questions is a good way to learn, there is also downside under these circumstances.
For the vector type, the only type class that's part of the definition is finite, but then, above, what I'm doing involves type class finite_UNIV, which is in src/HOL/Library/Cardinality.thy.
Trying to use card, like with card (UNIV::t123 set), won't work for type vec because you can't assume that type class finite_UNIV has been instantiated for the index set type. If I'm wrong here with what seems to be obvious now, I'd like to know.
Well, even though the function I defined, vector_length, doesn't try to take the cardinality of UNIV::'b set directly, with my example, the simplifier produces the goal CARD(t123) = (3::nat).
I speculate on what that means for myself, but I haven't tracked down CARD, so I keep my speculations to myself.
(End of update.)
140117 Final final final
Trying to use value to learn about the use of card led me astray. The value command is based on the code generator, and value will have type class requirements that aren't needed in general.
There's no requirement that the index set be instantiated for type class finite_UNIV. It's just that the logic needed to be able to use card (UNIV::('b::finite set)) has to be in place.
It seems like the logic should already be there in Multivariate_Analysis for anything I've done. Anything I've said is subject to error.
(End of update.)
Conclusion About My Experience Here with vec in Multivariate_Analysis
Using generalized index sets seems overly complex, at least for me. Vectors as lists seems like what I would want, like with Matrix.thy, but maybe things need to be complex at times.
The biggest pain is using typedef to create a type which has a finite universal set. I don't know how to easily create finite sets. I saw a comment in the past that it's best to stay away from typedef. It sounds good at first, that it creates a type based on a set, but it ends up being a hassle to deal with.
[I comment further here about finite, generalized index sets being used in vec. I have to resort to a ZFC definition, because I have no idea where textbooks are that formalize general mathematics with type theory. This wiki article shows a generalized Cartesian product:
Wiki: Infinite product definition using a finite or infinite index set
Key to the definition is that an infinite set can be used as the index set, such as the real numbers.
As far as using a finite set as an index set, any finite set of cardinality n can be put one-to-one with the natural numbers 1...n, and a finite, natural number ordering is normally how we would use a vector.
It's not that I don't believe that someone, somewhere needs vectors with a finite index set that's not the natural numbers, but all the math I've seen for vectors and matrices is vectors of length n::nat, or n::nat x m::nat matrices.
For myself, I would think that the best vector and matrix would be based on list, since the component location of a list is based on natural numbers. There's a lot of computational magic that comes from using an Isabelle/HOL list.]
What I worked Through to Get the Above
It took me a lot of work to work through this. I know much less of how to use Isabelle than much more.
(*It's much faster to start jEdit with Multivariate_Analysis as the logic.*)
theory i140107a__Multvariate_Ana_vec_length
imports Complex_Main Multivariate_Analysis (*"../../../iHelp/i"*)
begin
declare[[show_sorts=true]] (*Set false if you don't want typing shown.*)
declare[[show_brackets=true]]
(*---FINITE UNIVERSAL SET, NOT FINITE SET
*)
(*
First, we need to understand what `x::('a::finite)` means. It means that
`x` is a type for which the universal set of it's type is finite, where
the universal set is `UNIV::('a set)`. It does not mean that terms of type
`'a::finite` are finite sets.
The use of `typedef` below will hopefully make this clear. The following are
related to all of this, cntl-click on them to investigate them.
*)
term "x::('a::finite)"
term "finite::('a set => bool)" (*the finite predicate*)
term "UNIV::('a set) == top" (*UNIV is designated universal set in Set.thy.*)
term "finite (UNIV :: 'a set)"
term "finite (top :: 'a set)"
(*
It happens to be that the `finite` predicate is used in the definition of
type class `finite`. Here are some pertinent snippets, after which I comment
on them:
class top =
fixes top :: 'a ("⊤")
abbreviation UNIV :: "'a set" where
"UNIV == top"
class finite =
assumes finite_UNIV: "finite (UNIV :: 'a set)"
The `assumes` in the `finite` type-class specifies that constant `top::'a set`
is finite, where `top` can be seen as defined in type-class `top`. Thus, any
type of type-class `top` must have a `top` constant.
The constant `top` is in Orderings.thy, and the Orderings theory comes next
after HOL.thy, which is fundamental. As to why this use of the constant `top`
by type-class `finite` can make the universe of a type finite, I don't know.
*)
(*---DISCOVERING LOWER LEVEL SYNTAX TO WORK WITH
*)
(*
From the output panel, I copied the type shown for `term "v::('a ^ 'b)"`. I
then cntl-clicked on `vec` to take me to the `vec` definition.
*)
term "v::('a ^ 'b)"
term "v::('a,'b::finite) vec"
(*
The `typedef` command defines the `('a, 'b) vec` type as an element of a
particular set, in particular, as an element in the set of all functions of
type `('b::finite) => 'a`. I rename `vec` to `vec2` so I can experiment with
`vec2`.
*)
typedef ('a, 'b) vec2 = "UNIV :: (('b::finite) => 'a) set"
by(auto)
notation
Rep_vec2 (infixl "$$" 90)
(*
The `morphisms` command renamed `Rep_vec` and `Abs_vec` to `vec_nth` and
`vec_lambda`, but I don't rename them for `vec2`. To create the `vec_length`
function, I'll be using the `Rep` function, which is `vec_nth` for `vec`.
However, the `Abs` function comes into play further down with the concrete
examples. It's used to coerce a function into a type that uses the type
construcor `vec`.
*)
term "Rep_vec2::(('a, 'b::finite) vec2 => ('b::finite => 'a))"
term "Abs_vec2::(('a::finite => 'b) => ('b, 'a::finite) vec2)"
(*---FIGURING OUT HOW THE REP FUNCTION WORKS WITH 0, 1, OR 2 ARGS
*)
(*
To figure it all out, I need to study these Rep_t function types. The type
of terms without explicit typing have the type shown below them, with the
appropriate `vec` or `vec2`.
*)
term "op $"
term "vec_nth"
term "op $$"
term "Rep_vec2::(('a, 'b::finite) vec2 => ('b::finite => 'a))"
term "op $ x"
term "vec_nth x"
term "op $$ x"
term "(Rep_vec2 x)::('b::finite => 'a)"
term "x $ i"
term "op $ x i"
term "vec_nth x i"
term "x $$ i"
term "op $$ x i"
term "(Rep_vec2 (x::('a, 'b::finite) vec2) (i::('b::finite))) :: 'a"
(*
No brackets shows more clearly that `x $$ i` is the curried function
`Rep_vec2` taking the arguments `x::(('a, 'b::finite) vec2)` and
`i::('b::finite)`.
*)
term "Rep_vec2::('a, 'b::finite) vec2 => 'b::finite => 'a"
(*---THE FUNCTION FOR THE LENGTH OF A VECTOR*)
(*
This is based on your `card_diagonal`, but it's `card` of the range of
`vec_nth v`. You want `card` of the domain.
*)
theorem "{ (v $ i) | i. True } = {c. ? i. c = (v $ i)}"
by(simp)
definition range_size :: "('a, 'b::finite) vec => nat" where
"range_size v = card {c. ? i. c = (v $ i)}"
declare
range_size_def [simp add]
(*
This is the card of the domain of `(vec_nth v)::('b::finite => 'a)`. I use
`vec_nth v` just to emphasize that what we want is `card` of the domain.
*)
theorem "(vec_nth v) i = (v $ i)"
by(simp)
definition vec_length :: "('a, 'b::finite) vec => nat" where
"vec_length v = card {i. ? c. c = (vec_nth v) i}"
declare
vec_length_def [simp add]
theorem
"∀x y. vec_length (x::('a, 'b) vec) = vec_length (y::('a, 'b::finite) vec)"
by(simp)
(*---EXAMPLES TO TEST THINGS OUT
*)
(*
Creating some constants.
*)
typedecl cT
consts
c1::cT
c2::cT
c3::cT
(*
Creating a type using the set {c1,c2,c3}.
*)
typedef t123 = "{c1,c2,c3}"
by(auto)
(*
The functions Abs_t123 and Rep_t123 are created. I have to use Abs_t123 below
to coerce the type of `cT` to `t123`. Here, I show the type of `Abs_t123`.
*)
term "Abs_t123 :: (cT => t123)"
term "Abs_t123 c1 :: t123"
(*
Use these `declare` commands to do automatic `Abs` coercion. I comment
them out to show how I do coercions explicitly.
*)
(*declare [[coercion_enabled]]*)
(*declare [[coercion Abs_t123]]*)
(*
I have to instantiate type `t123` as type-class `finite`. It seems it should
be simple to prove, but I can't prove it, so I use `sorry`.
*)
instantiation t123 :: finite
begin
instance sorry
end
term "UNIV::t123 set"
term "card (UNIV::t123 set)"
theorem "card (UNIV::t123 set) = 3"
try0
oops
(*
Generalized vectors use an index set, in this case `{c1,c2,c3}`. A vector is
an element from the set `(('b::finite) => 'a) set`. Concretely, my vectors are
going to be from the set `(t123 => nat) set`. I define a vector by defining a
function `t123_to_0`. Using normal vector notation, it is the vector
`<0,0,0>`. Using ZFC ordered pair function notation, it is the set
{(c1,0),(c2,0),(c3,0)}.
*)
definition t123_to_0 :: "t123 => nat" where
"t123_to_0 x = 0"
declare
t123_to_0_def [simp add]
(*
I'm going to have to use `vec_lambda`, `vec_nth`, and `Abs_t123`, so I create
some `term` variations to look at types in the output panel, to try to figure
out how to mix and match functions and arguments.
*)
term "vec_lambda (f::('a::finite => 'b)) :: ('b, 'a::finite) vec"
term "vec_lambda t123_to_0 :: (nat, t123) vec"
term "vec_nth (vec_lambda t123_to_0)"
term "vec_nth (vec_lambda t123_to_0) (Abs_t123 c1)"
(*
The function `vec_length` seems to work. You'd think that `CARD(t123) = 3`
would be true. I try to cntl-click on `CARD`, but it doesn't work.
*)
theorem "vec_length (vec_lambda t123_to_0) = (3::nat)"
apply(simp)
(*GOAL: (CARD(t123) = (3::nat))*)
oops
theorem "(vec_nth (vec_lambda t123_to_0) (Abs_t123 c1)) = (0::nat)"
by(auto)
theorem "range_size (vec_lambda t123_to_0) = (1::nat)"
by(auto)
definition t123_to_x :: "t123 => t123" where
"t123_to_x x = x"
declare
t123_to_x_def [simp add]
theorem "(vec_nth (vec_lambda t123_to_x) (Abs_t123 c1)) = (Abs_t123 c1)"
by(auto)
theorem "(vec_nth (vec_lambda t123_to_x) (Abs_t123 c2)) = (Abs_t123 c2)"
by(auto)
(*THE LENGTH BASED SOLELY ON THE TYPE, NOT ON A PARTICULAR VECTOR
*)
(*Update 140111: The length of a vector is going to be the cardinality of the
universal set of the type, `UNIV::('a::finite set)`. For `t123`, the following
terms are involved.
*)
term "UNIV::t123 set"
term "top::t123 set"
term "card (UNIV::t123 set)" (*OUTPUT PANEL: CARD(t123)::nat.*)
term "card (top::t123 set)" (*OUTPUT PANEL: CARD(t123)::nat.*)
(*
It can be seen that `card (top::t123 set)` is the same as the theorem above
with the goal `CARD(t123) = (3::nat)`. What I didn't do above is instantiate
type `t123` for type-class `top`. I try to define `top_t123`, but it gives me
an error.
*)
instantiation t123 :: top
begin
definition top_t123 :: "t123 set" where
"top_t123 = {Abs_t123 c1, Abs_t123 c2, Abs_t123 c3}"
(*ERROR
Clash of specifications
"i140107a__Multvariate_Ana_vec_length.top_set_inst.top_set_def" and
"Set.top_set_inst.top_set_def" for constant "Orderings.top_class.top"
*)
instance sorry
end
(*To define the cardinality of type `t123` appears to be an involved process,
but maybe there's one easy type-class that can be instantiated that gives me
everything I need. The use of `value` shows that type `t123` needs to be
type-class `card_UNIV`, but `card_UNIV` is based on class `finite_UNIV`.
Understanding it all is involved enough to give job security to a person who
does understand it.
*)
value "card (top::t123 set)" (*ERROR: Type t123 not of sort card_UNIV.*)
term "card_UNIV"
term "finite_UNIV"
(******************************************************************************)
end
The First Parts of My Answer
(Because the imports weren't shown for the source, it wasn't obvious where any of the operators were coming from. There's also the Matrix AFP entry to confuse things. Additionally, other than atomic constants and variables in HOL, most everything is a function, so classifying something as a function doesn't clarify anything without some context. Providing source that won't produce errors helps. The normal entry point is Complex_Main. That sums up most of what I had said here. )
Links to Related Questions
[13-05-27] Isabelle: how to work with matrices
[13-05-30] Isabelle: transpose a matrix that includes a constant factor
[13-06-25] Isabelle matrix arithmetic: det_linear_row_setsum in library with different notation
[13-08-12] Isabelle: maximum value in a vector
[13-09-12] Degree of polynomial smaller than a number
[13-11-21] Isabelle: degree of polynomial multiplied with constant
[13-11-26] Isabelle: Power of a matrix (A^n)?
[13-12-01] Isabelle: difference between A * 1 and A ** mat 1
[14-01-17] Isabelle: Issue with setprod

Resources