10
1
mirror of https://gitlab.com/scemama/QCaml.git synced 2024-11-18 20:12:26 +01:00
QCaml/common/bitstring.org

561 lines
15 KiB
Org Mode
Raw Normal View History

2020-12-27 16:36:25 +01:00
#+begin_src elisp tangle: no :results none :exports none
2020-12-27 15:46:11 +01:00
(setq pwd (file-name-directory buffer-file-name))
(setq name (file-name-nondirectory (substring buffer-file-name 0 -4)))
(setq lib (concat pwd "lib/"))
(setq testdir (concat pwd "test/"))
(setq mli (concat lib name ".mli"))
(setq ml (concat lib name ".ml"))
(setq test-ml (concat testdir name ".ml"))
2020-12-27 13:43:55 +01:00
(org-babel-tangle)
2020-12-27 16:36:25 +01:00
#+end_src
2020-12-26 01:47:55 +01:00
* Bit string
:PROPERTIES:
:header-args: :noweb yes :comments both
:END:
We define here a data type to handle bit strings efficiently.
When the bit string contains less than 64 bits, it is stored
internally in a 63-bit integer and uses bitwise instructions.
When more than 63 bits are required, the =zarith= library is used to
consider the bit string as a multi-precision integer.
2020-12-27 16:36:25 +01:00
** Single-integer implementation :noexport:
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
module One = struct
let of_int x =
assert (x > 0); x
let numbits _ = 63
let zero = 0
let is_zero x = x = 0
let shift_left x i = x lsl i
let shift_right x i = x lsr i
let shift_left_one i = 1 lsl i
2020-12-27 16:36:25 +01:00
let testbit x i = ( (x lsr i) land 1 ) = 1
2020-12-26 01:47:55 +01:00
let logor a b = a lor b
2020-12-27 16:36:25 +01:00
let neg a = - a
2020-12-26 01:47:55 +01:00
let logxor a b = a lxor b
let logand a b = a land b
let lognot a = lnot a
let minus_one a = a - 1
let plus_one a = a + 1
let popcount = function
| 0 -> 0
2020-12-27 16:36:25 +01:00
| r -> Util.popcnt (Int64.of_int r)
2020-12-26 01:47:55 +01:00
2020-12-27 16:36:25 +01:00
let trailing_zeros r =
Util.trailz (Int64.of_int r)
2020-12-26 01:47:55 +01:00
let hamdist a b =
a lxor b
2020-12-27 16:36:25 +01:00
|> popcount
2020-12-26 01:47:55 +01:00
2020-12-27 16:36:25 +01:00
let pp ppf s =
Format.fprintf ppf "@[@[%a@]@]" (Util.pp_bitstring 64)
2020-12-26 01:47:55 +01:00
(Z.of_int s)
end
#+end_src
2020-12-27 16:36:25 +01:00
** Zarith implementation :noexport:
2020-12-26 01:47:55 +01:00
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
module Many = struct
let of_z x = x
let zero = Z.zero
let is_zero x = x = Z.zero
2020-12-27 16:36:25 +01:00
let shift_left = Z.shift_left
2020-12-26 01:47:55 +01:00
let shift_right = Z.shift_right
let shift_left_one i = Z.shift_left Z.one i
let testbit = Z.testbit
let logor = Z.logor
let logxor = Z.logxor
let logand = Z.logand
let lognot = Z.lognot
let neg = Z.neg
let minus_one = Z.pred
let plus_one = Z.succ
let trailing_zeros = Z.trailing_zeros
let hamdist = Z.hamdist
let numbits i = max (Z.numbits i) 64
2020-12-27 16:36:25 +01:00
let popcount z =
2020-12-26 01:47:55 +01:00
if z = Z.zero then 0 else Z.popcount z
2020-12-27 16:36:25 +01:00
let pp ppf s =
2020-12-26 01:47:55 +01:00
Format.fprintf ppf "@[@[%a@]@]" (Util.pp_bitstring (Z.numbits s)) s
end
#+end_src
** Type
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
type t
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
type t =
| One of int
| Many of Z.t
#+end_src
2020-12-27 16:36:25 +01:00
** Tests header :noexport:
2020-12-26 01:47:55 +01:00
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval test-ml)
2020-12-26 01:47:55 +01:00
open Common.Bitstring
let check msg x = Alcotest.(check bool) msg true x
let test_all () =
2020-12-27 17:38:04 +01:00
let x = 8745687 in
let one_x = of_int x in
let z = Z.shift_left (Z.of_int x) 64 in
let many_x = of_z z in
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-26 01:47:55 +01:00
** General implementation
2020-12-27 16:36:25 +01:00
2020-12-26 01:47:55 +01:00
*** ~of_int~
2020-12-27 16:36:25 +01:00
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val of_int : int -> t
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
Creates a bit string from an ~int~.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let of_int x =
One (One.of_int x)
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "of_x" true (one_x = (of_int x));
2020-12-26 01:47:55 +01:00
#+end_src
*** ~of_z~
2020-12-27 16:36:25 +01:00
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val of_z : Z.t -> t
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
Creates a bit string from an ~Z.t~ multi-precision integer.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let of_z x =
if Z.numbits x < 64 then One (Z.to_int x) else Many (Many.of_z x)
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "of_z" true (one_x = (of_z (Z.of_int x)));
2020-12-26 01:47:55 +01:00
#+end_src
*** ~zero~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val zero : int -> t
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
~zero n~ creates a zero bit string with ~n~ bits.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let zero = function
2020-12-27 17:38:04 +01:00
| n when n < 64 -> One (One.zero)
| _ -> Many (Many.zero)
2020-12-26 01:47:55 +01:00
#+end_src
*** ~numbits~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val numbits : t -> int
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
Returns the number of bits used to represent the bit string.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let numbits = function
2020-12-27 17:38:04 +01:00
| One x -> One.numbits x
| Many x -> Many.numbits x
2020-12-26 01:47:55 +01:00
#+end_src
*** ~is_zero~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val is_zero : t -> bool
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
True if all the bits of the bit string are zero.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let is_zero = function
| One x -> One.is_zero x
| Many x -> Many.is_zero x
#+end_src
*** ~neg~
2020-12-27 17:38:04 +01:00
#+begin_src ocaml :tangle (eval mli)
val neg : t -> t
#+end_src
2020-12-26 01:47:55 +01:00
Returns the negative of the integer interpretation of the bit string.
#+begin_example
neg (of_int x) = neg (of_int (-x))
#+end_example
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let neg = function
| One x -> One (One.neg x)
| Many x -> Many (Many.neg x)
#+end_src
*** ~shift_left~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val shift_left : t -> int -> t
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
~shift_left t n~ returns a new bit strings with all the bits
shifted ~n~ positions to the left.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let shift_left x i = match x with
2020-12-27 17:38:04 +01:00
| One x -> One (One.shift_left x i)
| Many x -> Many (Many.shift_left x i)
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "shift_left1" true (of_int (x lsl 3) = shift_left one_x 3);
Alcotest.(check bool) "shift_left2" true (of_z (Z.shift_left z 3) = shift_left many_x 3);
Alcotest.(check bool) "shift_left3" true (of_z (Z.shift_left z 100) = shift_left many_x 100);
2020-12-26 01:47:55 +01:00
#+end_src
*** ~shift_right~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val shift_right : t -> int -> t
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
~shift_right t n~ returns a new bit strings with all the bits
shifted ~n~ positions to the right.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let shift_right x i = match x with
2020-12-27 17:38:04 +01:00
| One x -> One (One.shift_right x i)
| Many x -> Many (Many.shift_right x i)
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "shift_right1" true (of_int (x lsr 3) = shift_right one_x 3);
Alcotest.(check bool) "shift_right2" true (of_z (Z.shift_right z 3) = shift_right many_x 3);
2020-12-26 01:47:55 +01:00
#+end_src
*** ~shift_left_one~
2020-12-27 17:38:04 +01:00
#+begin_src ocaml :tangle (eval mli)
val shift_left_one : int -> int -> t
#+end_src
2020-12-26 01:47:55 +01:00
~shift_left_one size n~ returns a new bit strings with the ~n~-th
bit set to one.
It is equivalent as shifting ~1~ by ~n~ bits to the left.
~size~ is the total number of bits of the bit string.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let shift_left_one = function
2020-12-27 17:38:04 +01:00
| n when n < 64 -> fun i -> One (One.shift_left_one i)
| _ -> fun i -> Many (Many.shift_left_one i)
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "shift_left_one1" true (of_int (1 lsl 3) = shift_left_one 4 3);
Alcotest.(check bool) "shift_left_one2" true (of_z (Z.shift_left Z.one 200) = shift_left_one 300 200);
2020-12-26 01:47:55 +01:00
#+end_src
*** ~testbit~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val testbit : t -> int -> bool
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-27 17:38:04 +01:00
~testbit t n~ is true if the ~n~-th bit of the bit string ~t~ is
set to ~1~.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let testbit = function
2020-12-27 17:38:04 +01:00
| One x -> One.testbit x
| Many x -> Many.testbit x
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "testbit1" true (testbit (of_int 8) 3);
Alcotest.(check bool) "testbit2" false (testbit (of_int 8) 2);
Alcotest.(check bool) "testbit3" false (testbit (of_int 8) 4);
Alcotest.(check bool) "testbit4" true (testbit (of_z (Z.of_int 8)) 3);
Alcotest.(check bool) "testbit5" false (testbit (of_z (Z.of_int 8)) 2);
Alcotest.(check bool) "testbit6" false (testbit (of_z (Z.of_int 8)) 4);
2020-12-26 01:47:55 +01:00
#+end_src
*** ~logor~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val logor : t -> t -> t
#+end_src
2020-12-27 17:38:04 +01:00
Bitwise logical or.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
let logor a b =
2020-12-26 01:47:55 +01:00
match a,b with
| One a, One b -> One (One.logor a b)
| Many a, Many b -> Many (Many.logor a b)
| _ -> invalid_arg "Bitstring.logor"
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "logor1" true (of_int (1 lor 2) = logor (of_int 1) (of_int 2));
Alcotest.(check bool) "logor2" true (of_z (Z.of_int (1 lor 2)) = logor (of_z Z.one) (of_z (Z.of_int 2)));
2020-12-26 01:47:55 +01:00
#+end_src
*** ~logxor~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val logxor : t -> t -> t
#+end_src
2020-12-27 17:38:04 +01:00
Bitwise logical exclusive or.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
let logxor a b =
2020-12-26 01:47:55 +01:00
match a,b with
| One a, One b -> One (One.logxor a b)
| Many a, Many b -> Many (Many.logxor a b)
| _ -> invalid_arg "Bitstring.logxor"
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "logxor1" true (of_int (1 lxor 2) = logxor (of_int 1) (of_int 2));
Alcotest.(check bool) "logxor2" true (of_z (Z.of_int (1 lxor 2)) = logxor (of_z Z.one) (of_z (Z.of_int 2)));
2020-12-26 01:47:55 +01:00
#+end_src
*** ~logand~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val logand : t -> t -> t
#+end_src
2020-12-27 17:38:04 +01:00
Bitwise logical and.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
let logand a b =
2020-12-26 01:47:55 +01:00
match a,b with
| One a, One b -> One (One.logand a b)
| Many a, Many b -> Many (Many.logand a b)
| _ -> invalid_arg "Bitstring.logand"
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
Alcotest.(check bool) "logand1" true (of_int (1 land 3) = logand (of_int 1) (of_int 3));
Alcotest.(check bool) "logand2" true (of_z (Z.of_int (1 land 3)) = logand (of_z Z.one) (of_z (Z.of_int 3)));
2020-12-26 01:47:55 +01:00
#+end_src
*** ~lognot~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-27 16:36:25 +01:00
val lognot : t -> t
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 17:38:04 +01:00
Bitwise logical negation.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let lognot = function
2020-12-27 17:38:04 +01:00
| One x -> One (One.lognot x)
| Many x -> Many (Many.lognot x)
2020-12-26 01:47:55 +01:00
#+end_src
*** ~minus_one~
2020-12-27 17:38:04 +01:00
#+begin_src ocaml :tangle (eval mli)
val minus_one : t -> t
#+end_src
2020-12-26 01:47:55 +01:00
Takes the integer representation of the bit string and removes one.
#+begin_example
minus_one (of_int 10) = of_int 9
#+end_example
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let minus_one = function
2020-12-27 17:38:04 +01:00
| One x -> One (One.minus_one x)
| Many x -> Many (Many.minus_one x)
2020-12-26 01:47:55 +01:00
#+end_src
*** ~plus_one~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val plus_one : t -> t
#+end_src
2020-12-27 17:38:04 +01:00
Takes the integer representation of the bit string and adds one.
#+begin_example
plus_one (of_int 10) = of_int 11
#+end_example
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let plus_one = function
2020-12-27 17:38:04 +01:00
| One x -> One (One.plus_one x)
| Many x -> Many (Many.plus_one x)
2020-12-26 01:47:55 +01:00
#+end_src
*** ~trailing_zeros~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val trailing_zeros : t -> int
#+end_src
2020-12-27 17:38:04 +01:00
Returns the number of trailing zeros in the bit string.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let trailing_zeros = function
2020-12-27 17:38:04 +01:00
| One x -> One.trailing_zeros x
| Many x -> Many.trailing_zeros x
2020-12-26 01:47:55 +01:00
#+end_src
*** ~hamdist~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val hamdist : t -> t -> int
#+end_src
2020-12-27 17:38:04 +01:00
Returns the Hamming distance, i.e. the number of bits differing
between two bit strings.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let hamdist a b = match a, b with
2020-12-27 17:38:04 +01:00
| One a, One b -> One.hamdist a b
| Many a, Many b -> Many.hamdist a b
| _ -> invalid_arg "Bitstring.hamdist"
2020-12-26 01:47:55 +01:00
#+end_src
*** ~popcount~
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val popcount : t -> int
#+end_src
2020-12-27 17:38:04 +01:00
Returns the number of bits set to one in the bit string.
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let popcount = function
2020-12-27 17:38:04 +01:00
| One x -> One.popcount x
| Many x -> Many.popcount x
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 16:36:25 +01:00
2020-12-26 01:47:55 +01:00
*** ~to_list~
2020-12-27 17:38:04 +01:00
#+begin_src ocaml :tangle (eval mli)
val to_list : ?accu:(int list) -> t -> int list
#+end_src
2020-12-26 01:47:55 +01:00
Converts a bit string into a list of integers indicating the
positions where the bits are set to ~1~. The first value for the
position is not ~0~ but ~1~.
2020-12-27 16:36:25 +01:00
2020-12-26 01:47:55 +01:00
#+begin_example
Bitstring.to_list (of_int 5);;
- : int list = [1; 3]
#+end_example
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let rec to_list ?(accu=[]) = function
| t when (is_zero t) -> List.rev accu
| t -> let newlist =
(trailing_zeros t + 1)::accu
2020-12-27 17:38:04 +01:00
in
logand t @@ minus_one t
|> (to_list [@tailcall]) ~accu:newlist
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 17:38:04 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
Alcotest.(check bool) "to_list" true ([ 1 ; 3 ; 4 ; 6 ] = (to_list (of_int 45)));
#+end_src
2020-12-26 01:47:55 +01:00
2020-12-26 01:54:39 +01:00
*** ~permutations~
2020-12-26 01:47:55 +01:00
2020-12-27 17:38:04 +01:00
#+begin_src ocaml :tangle (eval mli)
val permutations : int -> int -> t list
#+end_src
2020-12-26 01:54:39 +01:00
~permutations m n~ generates the list of all possible ~n~-bit
2020-12-26 01:47:55 +01:00
strings with ~m~ bits set to ~1~.
Algorithm adapted from [[https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation][Bit twiddling hacks]].
2020-12-27 16:36:25 +01:00
2020-12-26 01:47:55 +01:00
#+begin_example
2020-12-26 01:54:39 +01:00
Bitstring.permutations 2 4
2020-12-26 01:47:55 +01:00
|> List.map (fun x -> Format.asprintf "%a" Bitstring.pp x) ;;
- : string list =
["++--------------------------------------------------------------";
"+-+-------------------------------------------------------------";
"-++-------------------------------------------------------------";
"+--+------------------------------------------------------------";
"-+-+------------------------------------------------------------";
"--++------------------------------------------------------------"]
#+end_example
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
let permutations m n =
2020-12-26 01:47:55 +01:00
let rec aux k u rest =
if k=1 then
List.rev (u :: rest)
else
let t = logor u @@ minus_one u in
let t' = plus_one t in
let not_t = lognot t in
let neg_not_t = neg not_t in
let t'' = shift_right (minus_one @@ logand not_t neg_not_t) (trailing_zeros u + 1) in
(*
let t'' = shift_right (minus_one (logand (lognot t) t')) (trailing_zeros u + 1) in
,*)
(aux [@tailcall]) (k-1) (logor t' t'') (u :: rest)
in
aux (Util.binom n m) (minus_one (shift_left_one n m)) []
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-26 01:47:55 +01:00
check "permutations"
2020-12-26 01:54:39 +01:00
(permutations 2 4 = List.map of_int
2020-12-26 01:47:55 +01:00
[ 3 ; 5 ; 6 ; 9 ; 10 ; 12 ]);
#+end_src
** Printers
2020-12-27 15:46:11 +01:00
#+begin_src ocaml :tangle (eval mli)
2020-12-26 01:47:55 +01:00
val pp : Format.formatter -> t -> unit
#+end_src
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval ml) :exports none
2020-12-26 01:47:55 +01:00
let pp ppf = function
2020-12-27 17:38:04 +01:00
| One x -> One.pp ppf x
| Many x -> Many.pp ppf x
2020-12-26 01:47:55 +01:00
#+end_src
2020-12-27 16:36:25 +01:00
** Tests :noexport:
2020-12-26 01:47:55 +01:00
2020-12-27 16:36:25 +01:00
#+begin_src ocaml :tangle (eval test-ml) :exports none
2020-12-27 17:38:04 +01:00
()
2020-12-27 16:36:25 +01:00
2020-12-26 01:47:55 +01:00
let tests = [
2020-12-27 17:38:04 +01:00
"all", `Quick, test_all;
]
2020-12-26 01:47:55 +01:00
#+end_src