Trying to generalize a bit vector that uses typedef, bool list, and nat length

僤鯓⒐⒋嵵緔 提交于 2019-12-10 11:02:30

问题


I investigated Coq a little, with its dependent types. I have only the foggiest idea about it all, but now I have in mind that I want a bit vector as a bool list, in which the length of the vector is part of the type.

(This question is the possible predecessor of another question. In the next question, if I ask it, I'll ask whether I can recover what I lose, when I use typedef as below.)

(For this question, the question is at the bottom)

Here are the requirements for the type I want:

  • It has to use bool list, so that I can directly or indirectly do pattern matching and recursion on the list, and
  • the length of the vector has to be specified in the type.

Here is what I have:

typedef bitvec_4 = "{bl::bool list. length bl = 4}"
  by(auto, metis Ex_list_of_length)

It's important that the length of the list be part of the type, because I want to use the type with a definition, where all lists are known to be of the same size, like with this simple example:

definition two_bv4_to_bv4 :: "bitvec_4 => bitvec_4 => bitvec_4" where
  "two_bv4_to_bv4 x y = x"

What I don't want, in a theorem, is to have to specify the length of the lists. Type classes would eventually come into play somehow, but I want, as I say, the length to be specified in the type definition.

Definition and type signatures. Where do I let n = 4!!? (a tech joke of minimal humor-value)

Now, I try to generalize with a typedef like this, in which the length is a variable:

typedef bitvec_n = "{(bl::bool list, n::nat). length bl = n}"
  by(auto)

That's no good. In a definition like this next one, my type doesn't guarantee that all lists are of the same length:

definition two_bvn_to_bvn :: "bitvec_n => bitvec_n => bitvec_n" where
  "two_bvn_to_bvn x y = x"

The question? (I think so)

I've experimented a little with types like bitvec_4 above. If I don't run into big roadblocks, I might try to make big use of them.

I could define types like the above for powers of 2, up to, say, 1024 bits, along with type classes that reflect their common properties.

But, is there a better way to do this? It has to be somewhat straightforward, I think, with the use of bool list.

Update (got the answer for what it was actually about)

Based on Manuel's answer, I include here a self-contained theory.

It's mostly a duplication of Manuel's source, but at the end, my functions swap_bl and swap_2bv, along with the final use of value, show the end result of what I was trying to accomplish. My comments emphasize the problems that were on my mind, and possibly, my end application shows why I haven't looked to HOL/Word as a solution.

For a typedef type, to do pattern matching indirectly, similar to that with swap_bl and 2 bitvec, I was using the Abs and Rep functions together as inverses. One problem, as Manuel pointed out, is that I can feed an Abs function a bool list of the wrong length, and it won't give an error. Another big problem is the abstraction violations due to the use of the Abs function.

Those problems, and wanting to know if I could recover the use of value for my typedef type, would have been parts of my next question, but all that's been answered here.

theory i141210ac__testing_out_manuels_answer
imports Main "~~/src/HOL/Library/Numeral_Type"
begin
(*Basic type definition.*)
  typedef ('n::finite) bitvec = "{bs :: bool list. length bs = CARD('n)}"
    morphisms bitvec_to_list Abs_bitvec
    by (simp add: Ex_list_of_length)

  setup_lifting type_definition_bitvec

  lift_definition nth :: "('n::finite) bitvec => nat => bool" (infixl "$" 90) 
    is List.nth .

(*Can't use 'value' yet for 'nth', or I get an abstraction violation.*)
  term "(Abs_bitvec [True,False] :: 2 bitvec) $ 1"

(*Truncate or fill the list: needed to set things up for 'value'.*)
  definition set_length :: "nat => bool list => bool list" where
    "set_length n xs = (if length xs < n 
                        then xs @ replicate (n - length xs) False 
                        else take n xs)"              
  lemma length_set_length [simp]: "length (set_length n xs) = n"
    unfolding set_length_def by auto

  definition list_to_bitvec :: "bool list => ('n::finite) bitvec" where
    "list_to_bitvec xs = Abs_bitvec (set_length CARD('n) xs)"

(*Finishing the magic needed for 'value'.*)
  lemma list_to_bitvec_code [code abstract]:
    "bitvec_to_list (list_to_bitvec xs :: ('n::finite) bitvec) 
      = set_length CARD('n) xs"
    unfolding list_to_bitvec_def by(simp add: Abs_bitvec_inverse)

(*Inverses for lists of length 2: no abstraction violations.*)
  value "list_to_bitvec (bitvec_to_list x) :: 2 bitvec"
  value "bitvec_to_list (list_to_bitvec x :: 2 bitvec)"

(*The magic now kicks in for 'value' and 'nth'. Understanding is optional.*)
  value "(list_to_bitvec [True,False] :: 2 bitvec) $ 1" (*OUTPUT: False.*)

(*For my use, the primary context of all this is pattern matching on lists.
  I can't pattern match on a 'typedef' type directly with 'fun', because 
  it's not a 'datatype'. I do it indirectly.*)

fun swap_bl :: "bool list => bool list" where
  "swap_bl [a,b] = [b,a]"
 |"swap_bl _ = undefined"

definition swap_2bv :: "2 bitvec => 2 bitvec" where
  "swap_2bv bv = list_to_bitvec (swap_bl (bitvec_to_list bv))"

value "swap_2bv (list_to_bitvec [a,b] :: 2 bitvec)" (*
  OUTPUT: "Abs_bitvec [b, a]" :: "2 bitvec" *)

(*Whether that's all a good idea, that's about the future, but it appears the 
  hard work, recovering the use of 'value', along with generalizing length,
  has been done by Manuel, and the authors of Numeral_Type and its imports.*)
end

回答1:


Isabelle does not support dependent types, but there are ways to still do what you want to do. For instance, there is already a stack of type classes and type syntax for type-level natural numbers.

theory Scratch
imports Main "~~/src/HOL/Library/Numeral_Type"
begin

lemma "(UNIV :: 4 set) = {0,1,2,3}"
  by (subst UNIV_enum) eval

As you can see, the type 4 is a type that contains the numbers from 0 to 3. Incidentally, this can also be used for computations in modular arithmetic:

lemma "((2 + 3) :: 4) = 1" by simp
lemma "((2 * 3) :: 4) = 2" by simp

You can use these numeral types to parametrise your bit vectors with a length:

typedef ('n::finite) bitvec = "{bs :: bool list. length bs = CARD('n)}"
  morphisms bitvec_to_list Abs_bitvec
  by (simp add: Ex_list_of_length)

setup_lifting type_definition_bitvec

You can access the n-th element of a bit vector by lifting the nth function from Boolean lists to bit vectors, which works automatically:

lift_definition nth :: "('n::finite) bitvec ⇒ nat ⇒ bool" (infixl "$" 90) is List.nth .

Converting boolean lists to bit vectors is a bit tricky, because the list you get in might not have the correct length; the expression list_to_bitvec [True] :: 2 bitvec would typecheck, but is obviously problematic. You could solve this either by returning undefined or, perhaps more appropriate in this instance, filling up the list with False or truncating it to get the right length:

definition set_length :: "nat ⇒ bool list ⇒ bool list" where
  "set_length n xs = (if length xs < n then xs @ replicate (n - length xs) False else take n xs)"

lemma length_set_length[simp]: "length (set_length n xs) = n"
  unfolding set_length_def by auto

Now we can define a function that converts a list of Booleans to a bit vector:

definition list_to_bitvec :: "bool list ⇒ ('n::finite) bitvec" where
  "list_to_bitvec xs = Abs_bitvec (set_length CARD('n) xs)"

However, we are not allowed to use Abs_bitvec in code equations; if you tried to evaluate, say, list_to_bitvec [True] :: 1 bitvec, you would get an abstraction violation. We have to give an explicit code abstract equation in terms of the morphism list_to_bitvec:

lemma list_to_bitvec_code[code abstract]:
  "bitvec_to_list (list_to_bitvec xs :: ('n::finite) bitvec) = set_length CARD('n) xs"
  unfolding list_to_bitvec_def by (simp add: Abs_bitvec_inverse)

And now we are basically done and can do e.g. this:

definition myvec :: "4 bitvec" where "myvec = list_to_bitvec [True, False, True]"

value myvec
(* Output: "Abs_bitvec [True, False, True, False]" :: "4 bitvec" *)

value "myvec $ 2"
(* Output: "True" :: "bool" *)

Note that you always have to annotate the result of list_to_bitvec with its length; Isabelle can not infer the length.

You may also want to have a look at the Word theory in ~~/src/HOL/Word/; it implements machine words of fixed length with all kinds of bit operations like NOT, AND, OR, etc.:

value "42 AND 23 :: 32 word"
(* Output: "2" :: "32 word" *)

value "293 :: 8 word"
(* Output: "37" :: "8 word" *)

value "test_bit (42 :: 8 word) 1"
(* Output: "True" :: "bool" *)

value "set_bit (42 :: 8 word) 2 True"
(* Output: "46" :: "8 word" *)

value "(BITS i. i < 4) :: 8 word"
(* Output: "15" :: "8 word" *)

Another related type are the vectors in src/HOL/Library/Multivariate_Analysis/Finite_Cartesian_Product.



来源:https://stackoverflow.com/questions/27415275/trying-to-generalize-a-bit-vector-that-uses-typedef-bool-list-and-nat-length

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!