From e2b2324f3d32ffabfb35a405894b8ca249090e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franc=CC=A7ois=20Pottier?= <francois.pottier@inria.fr> Date: Fri, 24 Dec 2021 15:19:00 +0100 Subject: [PATCH] Split into three packages feat-core, feat, feat-num. --- CHANGES.md | 26 +++++ Makefile | 50 +++++--- demo/Test.ml | 41 +++++-- demo/dune | 5 - demo/with-feat-num/dune | 7 ++ demo/with-feat/dune | 7 ++ feat-core.opam | 19 +++ feat-core/BigIntSig.ml | 43 +++++++ {src => feat-core}/Enum.ml | 8 +- feat-core/Enum.mli | 14 +++ feat-core/EnumSig.ml | 130 +++++++++++++++++++++ {src => feat-core}/IFSeq.ml | 19 ++- {src => feat-core}/IFSeq.mli | 24 ++-- {src => feat-core}/IFSeqList.ml | 0 {src => feat-core}/IFSeqList.mli | 4 +- {src => feat-core}/IFSeqObj.ml | 16 +-- {src => feat-core}/IFSeqObj.mli | 17 +-- {src => feat-core}/IFSeqSig.ml | 69 +++++++---- {src => feat-core}/IFSeqSyn.ml | 16 +-- {src => feat-core}/IFSeqSyn.mli | 17 +-- {src => feat-core}/Makefile | 0 src/bigint.ml => feat-core/RandomBigInt.ml | 18 ++- feat-core/RandomBigInt.mli | 17 +++ feat-core/RandomSig.ml | 32 +++++ feat-core/dune | 6 + feat-num.opam | 19 +++ feat-num/Enum.ml | 11 ++ feat-num/Enum.mli | 11 ++ feat-num/IFSeq.ml | 11 ++ src/bigint.mli => feat-num/IFSeq.mli | 4 +- feat-num/Makefile | 3 + feat-num/Num.ml | 33 ++++++ feat-num/Num.mli | 13 +++ feat-num/dune | 6 + feat.opam | 5 +- feat/Enum.ml | 11 ++ feat/Enum.mli | 11 ++ feat/IFSeq.ml | 11 ++ feat/IFSeq.mli | 11 ++ feat/Makefile | 3 + feat/Num.ml | 11 ++ feat/Num.mli | 13 +++ feat/dune | 6 + src/Enum.mli | 113 ------------------ src/dune | 7 -- 45 files changed, 644 insertions(+), 274 deletions(-) create mode 100644 CHANGES.md delete mode 100644 demo/dune create mode 100644 demo/with-feat-num/dune create mode 100644 demo/with-feat/dune create mode 100644 feat-core.opam create mode 100644 feat-core/BigIntSig.ml rename {src => feat-core}/Enum.ml (97%) create mode 100644 feat-core/Enum.mli create mode 100644 feat-core/EnumSig.ml rename {src => feat-core}/IFSeq.ml (74%) rename {src => feat-core}/IFSeq.mli (54%) rename {src => feat-core}/IFSeqList.ml (100%) rename {src => feat-core}/IFSeqList.mli (90%) rename {src => feat-core}/IFSeqObj.ml (94%) rename {src => feat-core}/IFSeqObj.mli (76%) rename {src => feat-core}/IFSeqSig.ml (55%) rename {src => feat-core}/IFSeqSyn.ml (95%) rename {src => feat-core}/IFSeqSyn.mli (75%) rename {src => feat-core}/Makefile (100%) rename src/bigint.ml => feat-core/RandomBigInt.ml (86%) create mode 100644 feat-core/RandomBigInt.mli create mode 100644 feat-core/RandomSig.ml create mode 100644 feat-core/dune create mode 100644 feat-num.opam create mode 100644 feat-num/Enum.ml create mode 100644 feat-num/Enum.mli create mode 100644 feat-num/IFSeq.ml rename src/bigint.mli => feat-num/IFSeq.mli (90%) create mode 100644 feat-num/Makefile create mode 100644 feat-num/Num.ml create mode 100644 feat-num/Num.mli create mode 100644 feat-num/dune create mode 100644 feat/Enum.ml create mode 100644 feat/Enum.mli create mode 100644 feat/IFSeq.ml create mode 100644 feat/IFSeq.mli create mode 100644 feat/Makefile create mode 100644 feat/Num.ml create mode 100644 feat/Num.mli create mode 100644 feat/dune delete mode 100644 src/Enum.mli delete mode 100644 src/dune diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..d9fea0e --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,26 @@ +# CHANGES + +## 2021/12/24 + +* The library is now split in three packages: `feat-core`, `feat`, and + `feat-num`. `feat-core` is parameterized over an implementation of big + integers and over a random number generator. `feat` instantiates `feat-core` + with big integers from the library `zarith` and with OCaml's standard random + number generator. `feat-num` instantiates `feat-core` with big integers from + the library `num` and with OCaml's standard random number generator. The + packages `feat` and `feat-num` offer the same API and are interchangeable. + (See `demo/with-feat` and `demo/with-feat-num` to see how the same code can + be linked with either package.) The three submodules offered both by `feat` + and by `feat-num` are `Num`, `IFSeq`, and `Enum`. Compatibility with the + previous release of `feat` should be complete as long as only the submodules + `IFSeq` and `Enum` were used. (Contributed by Jonah Beckford; reviewed and + adapted by François Pottier.) + +* Avoid inadvertent uses of OCaml's polymorphic comparison operators on big + integers. + +* Improved documentation. + +## 2020/12/31 + +* Initial release. diff --git a/Makefile b/Makefile index f42699b..42dce89 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ # ------------------------------------------------------------------------------ -# The name of the library. +# The name of the repository. THIS := feat +# The libraries (topologically sorted). +THIS_COMMAS := feat-core,feat,feat-num +THIS_SPACES := feat-core feat feat-num + # The version number is automatically set to the current date, # unless DATE is defined on the command line. DATE := $(shell /bin/date +%Y%m%d) @@ -21,12 +25,13 @@ all: .PHONY: install install: - @ dune build -p $(THIS) - @ dune install -p $(THIS) + @ dune build -p $(THIS_COMMAS) + @ dune install -p $(THIS_COMMAS) .PHONY: clean clean: - @ rm -f *~ src/*~ dune-workspace.versions + @ rm -f dune-workspace.versions + @ $(FIND) . -name "*~" | xargs rm -f @ dune clean .PHONY: test @@ -35,7 +40,7 @@ test: .PHONY: uninstall uninstall: - @ ocamlfind remove $(THIS) || true + @ for t in $(THIS_SPACES) ; do ocamlfind remove $$t; done || true .PHONY: reinstall reinstall: uninstall @@ -43,18 +48,15 @@ reinstall: uninstall .PHONY: show show: reinstall - @ echo "#require \"feat\";;\n#show Feat;;" | ocaml + @ echo "#require \"feat-core\";;\n#require \"feat\";;\n#require \"feat-num\";;\n#show FeatCore;;\n#show Feat;;\n#show FeatNum;;" | ocaml .PHONY: pin pin: - @ opam pin add $(THIS) . + @ for d in $(THIS_SPACES) ; do opam pin --yes add $$d . ; done .PHONY: unpin unpin: - @ opam pin remove $(THIS) - -# This requires a version of headache that supports UTF-8; please use -# https://github.com/fpottier/headache + @ opam pin --yes remove $(THIS_SPACES) HEADACHE := headache LIBHEAD := $(shell pwd)/headers/library-header @@ -62,8 +64,10 @@ FIND := $(shell if command -v gfind >/dev/null ; then echo gfind ; else echo .PHONY: headache headache: - @ $(FIND) src -regex ".*\.ml\(i\|y\|l\)?" \ - -exec $(HEADACHE) -h $(LIBHEAD) "{}" ";" + @ for d in $(THIS_SPACES) demo ; do \ + $(FIND) $$d -regex ".*\.ml\(i\|y\|l\)?" \ + -exec $(HEADACHE) -h $(LIBHEAD) "{}" ";" ; \ + done .PHONY: release release: @@ -87,11 +91,16 @@ release: # Upload. (This automatically makes a .tar.gz archive available on gitlab.) @ git push @ git push --tags +# Done. + @ echo "Done." + @ echo "If happy, please type:" + @ echo " \"make publish\" to publish a new opam package" + @ echo " \"make export\" to upload the documentation to yquem.inria.fr" .PHONY: publish publish: # Publish an opam description. - @ opam publish -v $(DATE) $(THIS) $(ARCHIVE) . + @ opam publish -v $(DATE) $(THIS_SPACES) $(ARCHIVE) DOCDIR = _build/default/_doc/_html DOC = $(DOCDIR)/index.html @@ -135,6 +144,15 @@ VERSIONS := \ 4.09.0+bytecode-only \ 4.10.0 \ 4.11.1 \ + 4.12.0 \ + 4.13.0 \ + +.PHONY: switches +switches: + @ for v in $(VERSIONS) ; do \ + opam switch create $$v || \ + opam install --switch $$v --yes zarith seq fix num; \ + done .PHONY: versions versions: @@ -149,7 +167,7 @@ handiwork: @ current=`opam switch show` ; \ for v in $(VERSIONS) ; do \ opam switch $$v && \ - eval $$(opam env) && \ - opam install --yes zarith seq fix.20201120 ; \ + eval $$(opam env --switch=$$v) && \ + opam install --yes zarith seq fix.20201120 num; \ done ; \ opam switch $$current diff --git a/demo/Test.ml b/demo/Test.ml index 2166d32..8fd03be 100644 --- a/demo/Test.ml +++ b/demo/Test.ml @@ -1,6 +1,23 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +(* This demo is written in such a way as to work both with feat (which relies + on zarith) and with feat-num (which relies on num). Both feat and feat-num + expose a main module (named either Feat or FeatNum) with three submodules + named Num, IFSeq, and Enum. We assume that a suitable -open flags has been + passed, so these three submodules are available. *) + open Printf open Fix.Memoize.Int -open Feat.Enum +let succ i = Num.add i Num.one +open Enum (* -------------------------------------------------------------------------- *) @@ -37,7 +54,7 @@ let list_wb_tree : tree list enum = (* Enumerating binary trees with two elements in [0; 1]. *) let elem : int enum = - enum (Feat.IFSeq.up 0 2) + enum (IFSeq.up 0 2) let etree : tree enum = fix (fun tree -> @@ -48,12 +65,12 @@ let etree : tree enum = (* Testing a sequence. *) -open Feat.IFSeq +open IFSeq let rec subrange i j s accu = - if i < j then + if Num.lt i j then let accu = get s i :: accu in - subrange (Z.succ i) j s accu + subrange (succ i) j s accu else List.rev accu @@ -61,26 +78,26 @@ let subrange i j s = subrange i j s [] let range s = - subrange Z.zero (length s) s + subrange Num.zero (length s) s let test name s = printf "Testing %s...\n%!" name; (* Test [length]. *) - printf " Length: %s\n%!" (Z.to_string (length s)); + printf " Length: %s\n%!" (Num.to_string (length s)); (* By calling [range s], test [get] at every index within range. *) - assert (Z.equal (length s) (Z.of_int (List.length (range s)))); + assert (Num.equal (length s) (Num.of_int (List.length (range s)))); printf " Every random access succeeds.\n"; (* Test [foreach]. We check that it produces the same elements as [get], in the same order, and that it produces neither too few nor too many elements. *) - let i = ref Z.zero in + let i = ref Num.zero in foreach s (fun x1 -> - assert (Z.lt !i (length s)); + assert (Num.lt !i (length s)); let x2 = get s !i in assert (x1 = x2); (* element equality *) - i := Z.succ !i + i := succ !i ); - assert (Z.equal !i (length s)); + assert (Num.equal !i (length s)); printf " Iteration via foreach is consistent with random access.\n" (* -------------------------------------------------------------------------- *) diff --git a/demo/dune b/demo/dune deleted file mode 100644 index 386130f..0000000 --- a/demo/dune +++ /dev/null @@ -1,5 +0,0 @@ -(test - (name Test) - (libraries unix fix zarith feat) - (flags :standard "-w" "A-44") -) diff --git a/demo/with-feat-num/dune b/demo/with-feat-num/dune new file mode 100644 index 0000000..af5fb2b --- /dev/null +++ b/demo/with-feat-num/dune @@ -0,0 +1,7 @@ +(copy_files ../Test.ml) + +(test + (name Test) + (libraries fix feat-num) + (flags :standard "-w" "A-44-70" "-open" "FeatNum") +) diff --git a/demo/with-feat/dune b/demo/with-feat/dune new file mode 100644 index 0000000..72787e4 --- /dev/null +++ b/demo/with-feat/dune @@ -0,0 +1,7 @@ +(copy_files ../Test.ml) + +(test + (name Test) + (libraries fix feat) + (flags :standard "-w" "A-44-70" "-open" "Feat") +) diff --git a/feat-core.opam b/feat-core.opam new file mode 100644 index 0000000..0b58a57 --- /dev/null +++ b/feat-core.opam @@ -0,0 +1,19 @@ +name: "feat-core" +opam-version: "2.0" +maintainer: "francois.pottier@inria.fr" +authors: [ + "François Pottier <francois.pottier@inria.fr>" +] +homepage: "https://gitlab.inria.fr/fpottier/feat" +dev-repo: "git+https://gitlab.inria.fr/fpottier/feat.git" +bug-reports: "francois.pottier@inria.fr" +build: [ + ["dune" "build" "-p" name "-j" jobs] +] +depends: [ + "ocaml" { >= "4.03" } + "dune" { >= "1.3" } + "seq" + "fix" { >= "20181206" } +] +synopsis: "Facilities for enumerating and sampling algebraic data types" diff --git a/feat-core/BigIntSig.ml b/feat-core/BigIntSig.ml new file mode 100644 index 0000000..99e9ab7 --- /dev/null +++ b/feat-core/BigIntSig.ml @@ -0,0 +1,43 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +(**A signature for big numbers that is satisfied both by [Zarith] and + by the older, slower but license-friendly [Num] package. This minimal + signature is required by {!IFSeqSyn} and {!IFSeqObj}. *) +module type BASIC = sig + type t + val zero : t + val one : t + val pred : t -> t + val add : t -> t -> t + val sub : t -> t -> t + val mul : t -> t -> t + val div_rem : t -> t -> t * t + val equal : t -> t -> bool + val lt : t -> t -> bool + val of_int : int -> t + exception Overflow + val to_int : t -> int +end + +(**An extended signature for big numbers, providing more functionality. This + signature is required by {!RandomBigInt} and by the modules that depend + on it, such as {!IFSeq}. *) +module type EXTENDED = sig + include BASIC + val leq: t -> t -> bool + val geq: t -> t -> bool + val (/): t -> t -> t + val ( * ): t -> t -> t + val (mod): t -> t -> t + val (lsl): t -> int -> t + val (lor): t -> t -> t + val to_string: t -> string +end diff --git a/src/Enum.ml b/feat-core/Enum.ml similarity index 97% rename from src/Enum.ml rename to feat-core/Enum.ml index 89809c0..df49cda 100644 --- a/src/Enum.ml +++ b/feat-core/Enum.ml @@ -8,7 +8,11 @@ (* terms of the MIT license, as described in the file LICENSE. *) (******************************************************************************) -(* -------------------------------------------------------------------------- *) +open IFSeqSig + +module Make (IFSeq : IFSEQ_EXTENDED) = struct + +module IFSeq = IFSeq (* Core combinators. *) @@ -124,3 +128,5 @@ let rec sample m e i j k = IFSeq.sample m (e i) (fun () -> sample m e (i + 1) j k ()) else k + +end diff --git a/feat-core/Enum.mli b/feat-core/Enum.mli new file mode 100644 index 0000000..d5a205e --- /dev/null +++ b/feat-core/Enum.mli @@ -0,0 +1,14 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +open IFSeqSig +open EnumSig + +module Make (IFSeq : IFSEQ_EXTENDED) : ENUM with module IFSeq = IFSeq diff --git a/feat-core/EnumSig.ml b/feat-core/EnumSig.ml new file mode 100644 index 0000000..da07fc3 --- /dev/null +++ b/feat-core/EnumSig.ml @@ -0,0 +1,130 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +open IFSeqSig + +(**This is the result signature of the functor {!Enum.Make}. *) +module type ENUM = sig + + (**This implementation of implicit finite sequences is used as a building + block in the definition of the type {!type-enum}, which follows. *) + module IFSeq : IFSEQ_EXTENDED + + (**An enumeration of type ['a enum] can be loosely thought of as a set of + values of type ['a], equipped with a notion of size. More precisely, it + is a function of a size [s] to a subset of inhabitants of size [s], + presented as a sequence. + + We expose the fact that enumerations are functions, instead of making + [enum] an abstract type, because this allows the user to make recursive + definitions. It is up to the user to ensure that recursion is + well-founded; as a rule of thumb, every recursive call must appear under + {!pay}. It is also up to the user to take precautions so that these + functions have constant time complexity (beyond the cost of an + initialization phase). This is typically achieved by using a memoizing + fixed point combinator instead of an ordinary recursive definition. *) + type 'a enum = + int -> 'a IFSeq.seq + + (**[empty] is the empty enumeration. *) + val empty: 'a enum + + (**[zero] is a synonym for [empty]. *) + val zero : 'a enum + + (**The enumeration [just x] contains just the element [x], with size zero. + [just x] is equivalent to [finite [x]]. *) + val just: 'a -> 'a enum + + (**The enumeration [enum x] contains the elements in the sequence [xs], with + size zero. *) + val enum: 'a IFSeq.seq -> 'a enum + + (**The enumeration [pay e] contains the same elements as [e], with a size + that is increased by one with respect to [e]. *) + val pay: 'a enum -> 'a enum + + (**[sum e1 e2] is the union of the enumerations [e1] and [e2]. It is up to + the user to ensure that the sets [e1] and [e2] are disjoint. *) + val sum : 'a enum -> 'a enum -> 'a enum + + (**[(++)] is a synonym for [sum]. *) + val ( ++ ) : 'a enum -> 'a enum -> 'a enum + + (**[exists xs e] is the union of all enumerations of the form [e x], where + [x] is drawn from the list [xs]. (This is an indexed sum.) It is up to + the user to ensure that the sets [e1] and [e2] are disjoint. *) + val exists: 'a list -> ('a -> 'b enum) -> 'b enum + + (**[product e1 e2] is the Cartesian product of the enumerations + [e1] and [e2]. *) + val product: 'a enum -> 'b enum -> ('a * 'b) enum + + (**[( ** )] is a synonym for [product]. *) + val ( ** ) : 'a enum -> 'b enum -> ('a * 'b) enum + + (**[balanced_product e1 e2] is a subset of the Cartesian product [product e1 + e2] where the sizes of the left-hand and right-hand pair components must + differ by at most one. *) + val balanced_product: 'a enum -> 'b enum -> ('a * 'b) enum + + (**[( *-* )] is a synonym for [balanced_product]. *) + val ( *-* ) : 'a enum -> 'b enum -> ('a * 'b) enum + + (**[map phi e] is the image of the enumeration [e] through the function + [phi]. It is up to the user to ensure that [phi] is injective. *) + val map: ('a -> 'b) -> 'a enum -> 'b enum + + (**The enumeration [finite xs] contains the elements in the list [xs], with + size zero. *) + val finite: 'a list -> 'a enum + + (**[bool] is equivalent to [finite [false; true]]. *) + val bool: bool enum + + (**If [elem] is an enumeration of the type ['a], then [list elem] is an + enumeration of the type ['a list]. It is worth noting that every call to + [list elem] produces a fresh memoizing function, so (if possible) one + should avoid applying [list] twice to the same argument; that would be a + waste of time and space. *) + val list: 'a enum -> 'a list enum + + (**Suppose we wish to enumerate lists of elements, where the validity of an + element depends on which elements have appeared earlier in the list. For + instance, we might wish to enumerate lists of instructions, where the set + of permitted instructions at some point depends on the environment at + this point, and each instruction produces an updated environment. If + [fix] is a suitable fixed point combinator and if the function [elem] + describes how elements depend on environments and how elements affect + environments, then [dlist fix elem] is such an enumeration. Each list + node is considered to have size 1. Because the function [elem] produces a + list (as opposed to an enumeration), an element does not have a size. + + The fixed point combinator [fix] is typically of the form [curried fix], + where [fix] is a fixed point combinator for keys of type ['env * int]. + Memoization takes place at keys that are pairs of an environment and a + size. + + The function [elem] receives an environment and must return a list of + pairs of an element and an updated environment. *) + val dlist: + ('env -> 'a list enum) Fix.fix -> + ('env -> ('a * 'env) list) -> + ('env -> 'a list enum) + + (**[sample m e i j k] is a sequence of at most [m] elements of every size + comprised between [i] (included) and [j] (excluded) extracted out of the + enumeration [e], prepended in front of the existing sequence [k]. At + every size, if there at most [m] elements of this size, then all elements + of this size are produced; otherwise, a random sample of [m] elements of + this size is produced. *) + val sample: int -> 'a enum -> int -> int -> 'a Seq.t -> 'a Seq.t + +end diff --git a/src/IFSeq.ml b/feat-core/IFSeq.ml similarity index 74% rename from src/IFSeq.ml rename to feat-core/IFSeq.ml index cd21753..ce7bb70 100644 --- a/src/IFSeq.ml +++ b/feat-core/IFSeq.ml @@ -8,9 +8,10 @@ (* terms of the MIT license, as described in the file LICENSE. *) (******************************************************************************) -(* The default implementation of the signature SEQ is based on IFSeqSyn, - instantiated with the unbounded integers provided by [zarith]. *) +module Make (Z : BigIntSig.EXTENDED) (R : RandomSig.S) = struct +(* We have a choice between using IFSeqSyn and using IFSeqObj. We choose the + former. *) include IFSeqSyn.Make(Z) (* Iterated sum. *) @@ -23,18 +24,22 @@ let bigsum ss = let exists (xs : 'a list) (s : 'a -> 'b seq) : 'b seq = bigsum (List.map s xs) -(* Extract a randomly chosen sample of [m] elements out of a sequence [s]. *) +(* [sample] extracts a randomly chosen sample of [m] elements out of a + sequence [s]. *) (* We do not protect against repetitions, as they are unlikely when [s] is long. *) (* For some reason, [Z.random] does not exist, and [Random.int] stops - working at [2^30]. [Bigint.random] works around these problems. *) + working at [2^30]. [RandomBigInt.random] works around these problems. *) + +module RandomBigInt = + RandomBigInt.Make(Z)(R) let rec sample (m : int) (s : 'a seq) (k : 'a Seq.t) : 'a Seq.t = if m > 0 then fun () -> - let i = Bigint.random (length s) in + let i = RandomBigInt.random (length s) in let x = get s i in Seq.Cons (x, sample (m - 1) s k) else @@ -44,4 +49,6 @@ let rec sample (m : int) (s : 'a seq) (k : 'a Seq.t) : 'a Seq.t = otherwise produce a randomly chosen sample, as above. *) let sample (m : int) (s : 'a seq) (k : 'a Seq.t) : 'a Seq.t = - if length s <= Z.of_int m then to_seq s k else sample m s k + if Z.leq (length s) (Z.of_int m) then to_seq s k else sample m s k + +end diff --git a/src/IFSeq.mli b/feat-core/IFSeq.mli similarity index 54% rename from src/IFSeq.mli rename to feat-core/IFSeq.mli index d0c0cff..909c1bb 100644 --- a/src/IFSeq.mli +++ b/feat-core/IFSeq.mli @@ -10,20 +10,10 @@ open IFSeqSig -(* An implementation of the signature SEQ, - instantiated with unbounded integers. *) - -include IFSEQ with type index = Z.t - -(* Iterated sum. *) -val bigsum: 'a seq list -> 'a seq - -(* Indexed iterated sum. *) -val exists: 'a list -> ('a -> 'b seq) -> 'b seq - -(* [sample m s k] is an explicit sequence of at most [m] elements extracted - out of the implicit sequence [s], prepended in front of the existing - sequence [k]. If [length s] at most [m], then all elements of [s] are - produced. Otherwise, a random sample of [m] elements extracted out of - [s] is produced. *) -val sample: int -> 'a seq -> 'a Seq.t -> 'a Seq.t +(**[Make] constructs an implementation of the signature + {!IFSeqSig.IFSEQ_EXTENDED}. It is parameterized over an implementation of + big integers and a random number generator. *) +module Make + (Z : BigIntSig.EXTENDED) + (R : RandomSig.S) +: IFSEQ_EXTENDED with type index = Z.t diff --git a/src/IFSeqList.ml b/feat-core/IFSeqList.ml similarity index 100% rename from src/IFSeqList.ml rename to feat-core/IFSeqList.ml diff --git a/src/IFSeqList.mli b/feat-core/IFSeqList.mli similarity index 90% rename from src/IFSeqList.mli rename to feat-core/IFSeqList.mli index b4fd392..e4db19f 100644 --- a/src/IFSeqList.mli +++ b/feat-core/IFSeqList.mli @@ -12,5 +12,5 @@ open IFSeqSig -include IFSEQ with type index = int - and type 'a seq = 'a list +include IFSEQ_BASIC with type index = int + and type 'a seq = 'a list diff --git a/src/IFSeqObj.ml b/feat-core/IFSeqObj.ml similarity index 94% rename from src/IFSeqObj.ml rename to feat-core/IFSeqObj.ml index 6e8133c..9fd0e91 100644 --- a/src/IFSeqObj.ml +++ b/feat-core/IFSeqObj.ml @@ -16,21 +16,7 @@ under the assumption that the arithmetic operations provided by [Z] cost O(1) as well. *) -module Make (Z : sig - type t - val zero: t - val one: t - val of_int: int -> t - val pred: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div_rem: t -> t -> t * t - val equal: t -> t -> bool - val lt: t -> t -> bool - exception Overflow - val to_int: t -> int -end) = struct +module Make (Z : BigIntSig.BASIC) = struct type index = Z.t diff --git a/src/IFSeqObj.mli b/feat-core/IFSeqObj.mli similarity index 76% rename from src/IFSeqObj.mli rename to feat-core/IFSeqObj.mli index 661f8e4..bc5cb5a 100644 --- a/src/IFSeqObj.mli +++ b/feat-core/IFSeqObj.mli @@ -18,19 +18,4 @@ open IFSeqSig under the assumption that the arithmetic operations provided by [Z] cost O(1) as well. *) -module Make (Z : sig - type t - val zero: t - val one: t - val of_int: int -> t - val pred: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div_rem: t -> t -> t * t - val equal: t -> t -> bool - val lt: t -> t -> bool - exception Overflow - val to_int: t -> int -end) -: IFSEQ with type index = Z.t +module Make (Z : BigIntSig.BASIC) : IFSEQ_BASIC with type index = Z.t diff --git a/src/IFSeqSig.ml b/feat-core/IFSeqSig.ml similarity index 55% rename from src/IFSeqSig.ml rename to feat-core/IFSeqSig.ml index 4462569..343f692 100644 --- a/src/IFSeqSig.ml +++ b/feat-core/IFSeqSig.ml @@ -8,76 +8,103 @@ (* terms of the MIT license, as described in the file LICENSE. *) (******************************************************************************) -(* A signature for implicit finite sequences. *) +(**A signature for implicit finite sequences. -(* These sequences are implicit, which means that they are not explicitly + These sequences are implicit, which means that they are not explicitly represented in memory as actual sequences of elements; instead, they are described by a data structure which contains enough information to produce an arbitrary element upon request. This design decision imposes some constraints on the operations that can be efficiently supported; for - instance, [filter] is not supported. *) + instance, [filter] is not supported. -(* This signature forms an applicative functor. *) + This signature forms an applicative functor. *) +module type IFSEQ_BASIC = sig -module type IFSEQ = sig - - (* ['a seq] is the type of sequences whose elements have type ['a]. *) + (**['a seq] is the type of sequences whose elements have type ['a]. *) type 'a seq - (* Constructors. *) + (**Constructors. *) - (* [empty] is a sequence of length zero. *) + (**[empty] is a sequence of length zero. *) val empty: 'a seq + + (**[zero] is a synonym for [empty]. *) val zero : 'a seq - (* [singleton x] is a sequence of length one whose single element is [x]. *) + (**[singleton x] is a sequence of length one whose single element is [x]. *) val singleton: 'a -> 'a seq + + (**[one] is a synonym for [singleton]. *) val one: 'a -> 'a seq - (* [rev xs] is the reverse of the sequence [xs]. *) + (**[rev xs] is the reverse of the sequence [xs]. *) val rev: 'a seq -> 'a seq - (* [sum s1 s2] is the concatenation of the sequences [s1] and [s2]. *) + (**[sum s1 s2] is the concatenation of the sequences [s1] and [s2]. *) val sum : 'a seq -> 'a seq -> 'a seq + + (**[(++)] is a synonym for [sum]. *) val ( ++ ) : 'a seq -> 'a seq -> 'a seq - (* [product s1 s2] is the Cartesian product of the sequences [s1] and [s2]. + (**[product s1 s2] is the Cartesian product of the sequences [s1] and [s2]. Its length is the product of the lengths of [s1] and [s2]. The first pair component is considered most significant. *) val product: 'a seq -> 'b seq -> ('a * 'b) seq + + (**[( ** )] is a synonym for [product]. *) val ( ** ) : 'a seq -> 'b seq -> ('a * 'b) seq - (* [map phi s] is the image of the sequence [s] through the function [phi]. + (**[map phi s] is the image of the sequence [s] through the function [phi]. If the user wishes to work with sequences of pairwise distinct elements, then [phi] should be injective. If furthermore the user wishes to work with sequences that enumerate all elements of a type, then [phi] should be surjective. *) val map: ('a -> 'b) -> 'a seq -> 'b seq - (* [up i j] is the sequence of the integers from [i] included up to [j] + (**[up i j] is the sequence of the integers from [i] included up to [j] excluded. *) val up: int -> int -> int seq (* Observations. *) - (* The type [index] is the type of integers used to represent indices and + (**The type [index] is the type of integers used to represent indices and lengths. *) type index - (* [length s] is the length of the sequence [s]. *) + (**[length s] is the length of the sequence [s]. *) val length: 'a seq -> index - (* [get s i] is the [i]-th element of the sequence [s]. The index [i] must + (**[get s i] is the [i]-th element of the sequence [s]. The index [i] must be comprised between zero included and [length s] excluded. *) val get: 'a seq -> index -> 'a - (* [foreach s k] iterates over all elements of the sequence [s]. Each element - in turn is passed to the loop body [k]. *) + (**[foreach s k] iterates over all elements of the sequence [s]. Each + element in turn is passed to the loop body [k]. *) val foreach: 'a seq -> ('a -> unit) -> unit - (* [to_seq s k] produces an explicit representation of the sequence [s] as a + (**[to_seq s k] produces an explicit representation of the sequence [s] as a sequence in the sense of OCaml's standard library module [Seq]. This sequence is prepended in front of the existing sequence [k]. *) val to_seq: 'a seq -> 'a Seq.t -> 'a Seq.t end + +(**This signature extends {!IFSEQ_BASIC} with more operations. *) +module type IFSEQ_EXTENDED = sig + + include IFSEQ_BASIC + + (**Iterated sum. *) + val bigsum: 'a seq list -> 'a seq + + (**Indexed iterated sum. *) + val exists: 'a list -> ('a -> 'b seq) -> 'b seq + + (**[sample m s k] is an explicit sequence of at most [m] elements extracted + out of the implicit sequence [s], prepended in front of the existing + sequence [k]. If [length s] at most [m], then all elements of [s] are + produced. Otherwise, a random sample of [m] elements extracted out of [s] + is produced. *) + val sample: int -> 'a seq -> 'a Seq.t -> 'a Seq.t + +end diff --git a/src/IFSeqSyn.ml b/feat-core/IFSeqSyn.ml similarity index 95% rename from src/IFSeqSyn.ml rename to feat-core/IFSeqSyn.ml index f01df79..549bd76 100644 --- a/src/IFSeqSyn.ml +++ b/feat-core/IFSeqSyn.ml @@ -18,21 +18,7 @@ under the assumption that the arithmetic operations provided by [Z] cost O(1) as well. *) -module Make (Z : sig - type t - val zero: t - val one: t - val of_int: int -> t - val pred: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div_rem: t -> t -> t * t - val equal: t -> t -> bool - val lt: t -> t -> bool - exception Overflow - val to_int: t -> int -end) = struct +module Make (Z : BigIntSig.BASIC) = struct type index = Z.t diff --git a/src/IFSeqSyn.mli b/feat-core/IFSeqSyn.mli similarity index 75% rename from src/IFSeqSyn.mli rename to feat-core/IFSeqSyn.mli index 81a4c57..734fe5a 100644 --- a/src/IFSeqSyn.mli +++ b/feat-core/IFSeqSyn.mli @@ -17,19 +17,4 @@ open IFSeqSig under the assumption that the arithmetic operations provided by [Z] cost O(1) as well. *) -module Make (Z : sig - type t - val zero: t - val one: t - val of_int: int -> t - val pred: t -> t - val add: t -> t -> t - val sub: t -> t -> t - val mul: t -> t -> t - val div_rem: t -> t -> t * t - val equal: t -> t -> bool - val lt: t -> t -> bool - exception Overflow - val to_int: t -> int -end) -: IFSEQ with type index = Z.t +module Make (Z : BigIntSig.BASIC) : IFSEQ_BASIC with type index = Z.t diff --git a/src/Makefile b/feat-core/Makefile similarity index 100% rename from src/Makefile rename to feat-core/Makefile diff --git a/src/bigint.ml b/feat-core/RandomBigInt.ml similarity index 86% rename from src/bigint.ml rename to feat-core/RandomBigInt.ml index e1ccd36..70fdb21 100644 --- a/src/bigint.ml +++ b/feat-core/RandomBigInt.ml @@ -12,7 +12,7 @@ Street's bignum library. *) (* [random state range] chooses a [depth] and generates random values using - [Random.State.bits state], called [1 lsl depth] times and concatenated. The + [R.bits state], called [1 lsl depth] times and concatenated. The preliminary result [n] therefore satisfies [0 <= n < 1 lsl (30 lsl depth)]. In order for the random choice to be uniform between [0] and [range-1], @@ -23,6 +23,10 @@ The [depth] value is chosen so that repeating is uncommon (1 in 1000 or less). *) +open Printf + +module Make (Z : BigIntSig.EXTENDED) (R : RandomSig.S) = struct + let bits_at_depth (depth : int) : int = 30 lsl depth @@ -36,9 +40,9 @@ let rec choose_bit_depth_for_range_from range depth = let choose_bit_depth_for_range (range : Z.t) : int = choose_bit_depth_for_range_from range 0 -let rec random_bigint_at_depth (state : Random.State.t) depth : Z.t = +let rec random_bigint_at_depth (state : R.State.t) depth : Z.t = if depth = 0 then - Z.of_int (Random.State.bits state) + Z.of_int (R.State.bits state) else let depth = depth - 1 in let prefix = random_bigint_at_depth state depth in @@ -62,11 +66,13 @@ let large_random state range = let random state range = if Z.leq range Z.zero then - failwith (Printf.sprintf "Bigint.random: argument %s <= 0" (Z.to_string range)) + invalid_arg (sprintf "random: %s is not positive" (Z.to_string range)) else if Z.lt range Z.(one lsl 30) then - Z.of_int (Random.State.int state (Z.to_int range)) + Z.of_int (R.State.int state (Z.to_int range)) else large_random state range let random range = - random (Random.get_state()) range + random (R.get_state ()) range + +end diff --git a/feat-core/RandomBigInt.mli b/feat-core/RandomBigInt.mli new file mode 100644 index 0000000..a86255a --- /dev/null +++ b/feat-core/RandomBigInt.mli @@ -0,0 +1,17 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +(* Uniform random generation of large integers. *) + +module Make (Z : BigIntSig.EXTENDED) (R : RandomSig.S) : sig + (**[random range] generates a random number comprised between 0 (included) + and [range] (excluded). [range] must be positive. *) + val random: Z.t -> Z.t +end diff --git a/feat-core/RandomSig.ml b/feat-core/RandomSig.ml new file mode 100644 index 0000000..2ba634e --- /dev/null +++ b/feat-core/RandomSig.ml @@ -0,0 +1,32 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +(** A subset of the signature of the module {!Stdlib.Random}. *) +module type S = sig + + module State : sig + + (** The state of the random number generator. *) + type t + + (** [bits s] returns 30 random bits in a nonnegative integer. *) + val bits : t -> int + + (** [int bound] returns a random integer comprised between 0 (inclusive) + and [bound] (exclusive). [bound] must be greater than 0 and less than + 2{^30}. *) + val int : t -> int -> int + + end + + (** [get_state()] returns the current state of the generator. *) + val get_state : unit -> State.t + +end diff --git a/feat-core/dune b/feat-core/dune new file mode 100644 index 0000000..5bf681a --- /dev/null +++ b/feat-core/dune @@ -0,0 +1,6 @@ +(library + (name FeatCore) + (public_name feat-core) + (flags "-w" "A-44-67-70") + (libraries seq fix) +) diff --git a/feat-num.opam b/feat-num.opam new file mode 100644 index 0000000..838201f --- /dev/null +++ b/feat-num.opam @@ -0,0 +1,19 @@ +name: "feat-num" +opam-version: "2.0" +maintainer: "francois.pottier@inria.fr" +authors: [ + "François Pottier <francois.pottier@inria.fr>" +] +homepage: "https://gitlab.inria.fr/fpottier/feat" +dev-repo: "git+https://gitlab.inria.fr/fpottier/feat.git" +bug-reports: "francois.pottier@inria.fr" +build: [ + ["dune" "build" "-p" name "-j" jobs] +] +depends: [ + "ocaml" { >= "4.03" } + "dune" { >= "1.3" } + "feat-core" + "num" +] +synopsis: "Facilities for enumerating and sampling algebraic data types, using Num for big numbers" diff --git a/feat-num/Enum.ml b/feat-num/Enum.ml new file mode 100644 index 0000000..f10b19b --- /dev/null +++ b/feat-num/Enum.ml @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include FeatCore.Enum.Make(IFSeq) diff --git a/feat-num/Enum.mli b/feat-num/Enum.mli new file mode 100644 index 0000000..ec0de7c --- /dev/null +++ b/feat-num/Enum.mli @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include FeatCore.EnumSig.ENUM with module IFSeq = IFSeq diff --git a/feat-num/IFSeq.ml b/feat-num/IFSeq.ml new file mode 100644 index 0000000..46138c8 --- /dev/null +++ b/feat-num/IFSeq.ml @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include FeatCore.IFSeq.Make(Num)(Random) diff --git a/src/bigint.mli b/feat-num/IFSeq.mli similarity index 90% rename from src/bigint.mli rename to feat-num/IFSeq.mli index b1358ee..0ae02c5 100644 --- a/src/bigint.mli +++ b/feat-num/IFSeq.mli @@ -8,6 +8,4 @@ (* terms of the MIT license, as described in the file LICENSE. *) (******************************************************************************) -(* Uniform random generation of large integers. *) - -val random: Z.t -> Z.t +include FeatCore.IFSeqSig.IFSEQ_EXTENDED with type index = Num.t diff --git a/feat-num/Makefile b/feat-num/Makefile new file mode 100644 index 0000000..3cf0f89 --- /dev/null +++ b/feat-num/Makefile @@ -0,0 +1,3 @@ +.PHONY: all +all: + @ make -C .. diff --git a/feat-num/Num.ml b/feat-num/Num.ml new file mode 100644 index 0000000..db81af3 --- /dev/null +++ b/feat-num/Num.ml @@ -0,0 +1,33 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +open Big_int + +type t = big_int +let zero = zero_big_int +let one = big_int_of_int 1 +let pred = pred_big_int +let add = add_big_int +let sub = sub_big_int +let mul = mult_big_int +let div_rem = quomod_big_int +let equal = eq_big_int +let lt = lt_big_int +let of_int = big_int_of_int +exception Overflow +let to_int = try int_of_big_int with Failure _ -> raise Overflow +let leq = le_big_int +let geq = ge_big_int +let (/) = div_big_int +let ( * ) = mult_big_int +let (mod) = mod_big_int +let (lsl) = shift_left_big_int +let (lor) = or_big_int +let to_string = string_of_big_int diff --git a/feat-num/Num.mli b/feat-num/Num.mli new file mode 100644 index 0000000..1f96177 --- /dev/null +++ b/feat-num/Num.mli @@ -0,0 +1,13 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +(* This module satisfies the signature [BigIntSig.EXTENDED], instantiated with + unbounded integers provided by the library [num]. *) +include FeatCore.BigIntSig.EXTENDED with type t = Big_int.big_int diff --git a/feat-num/dune b/feat-num/dune new file mode 100644 index 0000000..ca532ec --- /dev/null +++ b/feat-num/dune @@ -0,0 +1,6 @@ +(library + (name FeatNum) + (public_name feat-num) + (flags "-w" "A-44") + (libraries feat-core num) +) diff --git a/feat.opam b/feat.opam index dbec49e..2f312fd 100644 --- a/feat.opam +++ b/feat.opam @@ -13,8 +13,7 @@ build: [ depends: [ "ocaml" { >= "4.03" } "dune" { >= "1.3" } + "feat-core" "zarith" - "seq" - "fix" { >= "20181206" } ] -synopsis: "Facilities for enumerating and sampling algebraic data types" +synopsis: "Facilities for enumerating and sampling algebraic data types, using Zarith for big numbers" diff --git a/feat/Enum.ml b/feat/Enum.ml new file mode 100644 index 0000000..f10b19b --- /dev/null +++ b/feat/Enum.ml @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include FeatCore.Enum.Make(IFSeq) diff --git a/feat/Enum.mli b/feat/Enum.mli new file mode 100644 index 0000000..ec0de7c --- /dev/null +++ b/feat/Enum.mli @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include FeatCore.EnumSig.ENUM with module IFSeq = IFSeq diff --git a/feat/IFSeq.ml b/feat/IFSeq.ml new file mode 100644 index 0000000..46138c8 --- /dev/null +++ b/feat/IFSeq.ml @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include FeatCore.IFSeq.Make(Num)(Random) diff --git a/feat/IFSeq.mli b/feat/IFSeq.mli new file mode 100644 index 0000000..0ae02c5 --- /dev/null +++ b/feat/IFSeq.mli @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include FeatCore.IFSeqSig.IFSEQ_EXTENDED with type index = Num.t diff --git a/feat/Makefile b/feat/Makefile new file mode 100644 index 0000000..3cf0f89 --- /dev/null +++ b/feat/Makefile @@ -0,0 +1,3 @@ +.PHONY: all +all: + @ make -C .. diff --git a/feat/Num.ml b/feat/Num.ml new file mode 100644 index 0000000..94e5247 --- /dev/null +++ b/feat/Num.ml @@ -0,0 +1,11 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +include Z diff --git a/feat/Num.mli b/feat/Num.mli new file mode 100644 index 0000000..4c771fc --- /dev/null +++ b/feat/Num.mli @@ -0,0 +1,13 @@ +(******************************************************************************) +(* *) +(* Feat *) +(* *) +(* François Pottier, Inria Paris *) +(* *) +(* Copyright Inria. All rights reserved. This file is distributed under the *) +(* terms of the MIT license, as described in the file LICENSE. *) +(******************************************************************************) + +(* This module satisfies the signature [BigIntSig.EXTENDED], + instantiated with unbounded integers from [zarith]. *) +include FeatCore.BigIntSig.EXTENDED with type t = Z.t diff --git a/feat/dune b/feat/dune new file mode 100644 index 0000000..363d534 --- /dev/null +++ b/feat/dune @@ -0,0 +1,6 @@ +(library + (name Feat) + (public_name feat) + (flags "-w" "A-44") + (libraries feat-core zarith) +) diff --git a/src/Enum.mli b/src/Enum.mli deleted file mode 100644 index 0b16b75..0000000 --- a/src/Enum.mli +++ /dev/null @@ -1,113 +0,0 @@ -(******************************************************************************) -(* *) -(* Feat *) -(* *) -(* François Pottier, Inria Paris *) -(* *) -(* Copyright Inria. All rights reserved. This file is distributed under the *) -(* terms of the MIT license, as described in the file LICENSE. *) -(******************************************************************************) - -(* An enumeration of type ['a enum] can be loosely thought of as a set of - values of type ['a], equipped with a notion of size. More precisely, it - is a function of a size [s] to a subset of inhabitants of size [s], - presented as a sequence. *) - -(* We expose the fact that enumerations are functions, instead of making [enum] - an abstract type, because this allows the user to make recursive definitions. - It is up to the user to ensure that recursion is well-founded; as a rule of - thumb, every recursive call must appear under [pay]. It is also up to the - user to take precautions so that these functions have constant time - complexity (beyond the cost of an initialization phase). This is typically - achieved by using a memoizing fixed point combinator [fix] instead of - ordinary recursive definitions. *) - -type 'a enum = - int -> 'a IFSeq.seq - -(* [empty] is the empty enumeration. *) -val empty: 'a enum -val zero : 'a enum - -(* The enumeration [just x] contains just the element [x]. - Its size is considered to be zero. *) -val just: 'a -> 'a enum - -(* The enumeration [enum x] contains the elements in the sequence [xs]. - Their size is considered to be zero. *) -val enum: 'a IFSeq.seq -> 'a enum - -(* The enumeration [pay e] contains the same elements as [e], - but their size is increased by one. *) -val pay: 'a enum -> 'a enum - -(* [sum e1 e2] is the union of the enumerations [e1] and [e2]. It is up - to the user to ensure that the sets [e1] and [e2] are disjoint. *) -val sum : 'a enum -> 'a enum -> 'a enum -val ( ++ ) : 'a enum -> 'a enum -> 'a enum - -(* [exists xs e] is the union of all enumerations of the form [e x], where [x] - is drawn from the list [xs]. (This is an indexed sum.) It is up to the user - to ensure that the sets [e1] and [e2] are disjoint. *) -val exists: 'a list -> ('a -> 'b enum) -> 'b enum - -(* [product e1 e2] is the Cartesian product of the enumerations - [e1] and [e2]. *) -val product: 'a enum -> 'b enum -> ('a * 'b) enum -val ( ** ) : 'a enum -> 'b enum -> ('a * 'b) enum - -(* [product e1 e2] is a subset of the Cartesian product [product e1 e2] - where the sizes of the left-hand and right-hand pair components must - differ by at most one. *) -val balanced_product: 'a enum -> 'b enum -> ('a * 'b) enum -val ( *-* ) : 'a enum -> 'b enum -> ('a * 'b) enum - -(* [map phi e] is the image of the enumeration [e] through the function [phi]. - It is up to the user to ensure that [phi] is injective. *) -val map: ('a -> 'b) -> 'a enum -> 'b enum - -(* The enumeration [finite xs] contains the elements in the list [xs]. - They are considered to have size zero. *) -val finite: 'a list -> 'a enum - -(* [bool] is the enumeration [false; true]. *) -val bool: bool enum - -(* If [elem] is an enumeration of the type ['a], then [list elem] is an - enumeration of the type ['a list]. It is worth noting that every call - to [list elem] produces a fresh memoizing function, so (if possible) - one should avoid applying [list] twice to the same argument; that - would be a waste of time and space. *) -val list: 'a enum -> 'a list enum - -(* Suppose we wish to enumerate lists of elements, where the validity of an - element depends on which elements have appeared earlier in the list. For - instance, we might wish to enumerate lists of instructions, where the set - of permitted instructions at some point depends on the environment at this - point, and each instruction produces an updated environment. If [fix] is a - suitable fixed point combinator and if the function [elem] describes how - elements depend on environments and how elements affect environments, then - [dlist fix elem] is such an enumeration. Each list node is considered to - have size 1. Because the function [elem] produces a list (as opposed to an - enumeration), an element does not have a size. *) - -(* The fixed point combinator [fix] is typically of the form [curried fix], - where [fix] is a fixed point combinator for keys of type ['env * int]. - Memoization takes place at keys that are pairs of an environment and a - size. *) - -(* The function [elem] receives an environment and must return a list of pairs - of an element and an updated environment. *) - -val dlist: - ('env -> 'a list enum) Fix.fix -> - ('env -> ('a * 'env) list) -> - ('env -> 'a list enum) - -(* [sample m e i j k] is a sequence of at most [m] elements of every size - comprised between [i] (included) and [j] (excluded) extracted out of the - enumeration [e], prepended in front of the existing sequence [k]. At every - size, if there at most [m] elements of this size, then all elements of this - size are produced; otherwise, a random sample of [m] elements of this size - is produced. *) -val sample: int -> 'a enum -> int -> int -> 'a Seq.t -> 'a Seq.t diff --git a/src/dune b/src/dune deleted file mode 100644 index 90a5a6c..0000000 --- a/src/dune +++ /dev/null @@ -1,7 +0,0 @@ -(library - (name feat) - (public_name feat) - (synopsis "Facilities for enumerating and sampling algebraic data types") - (flags "-w" "A-44") - (libraries seq zarith fix) -) -- GitLab