package feat-core

  1. Overview
  2. Docs
Facilities for enumerating and sampling algebraic data types

Install

Dune Dependency

Authors

Maintainers

Sources

archive.tar.gz
md5=f8548ba0792a07d2b72c7894d1089d5e
sha512=6c53ad4f898c074b888018269fe2c00bf001fb5b22ceade1e7e26479fbe9ef55fe97d04a757b10232565a6af8f51d960b6f5f494552df4205aba046b075c513b

doc/src/feat-core/IFSeqSyn.ml.html

Source file IFSeqSyn.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
(******************************************************************************)
(*                                                                            *)
(*                                     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 is an implementation of implicit finite sequences as syntax, that is,
   algebraic data structures. This style should be more efficient than the one
   used in IFSeqObj, because fewer memory blocks are allocated (one block per
   construct instead of typically three) and because it opens the door to
   rebalancing schemes -- e.g., trees of binary [Sum] nodes can be balanced. *)

(* In this implementation, the constructors have time complexity O(1),
   under the assumption that the arithmetic operations provided by [Z]
   cost O(1) as well. *)

module Make (Z : BigIntSig.BASIC) = struct

type index =
  Z.t

(* The data constructors [Rev], [Sum], [Product], [Map] are annotated with the
   length of the sequence. *)

(* The child of [Rev] cannot be [Empty], [Singleton], or [Rev]. *)

(* The children of [Sum], [Product], [Map] cannot be [Empty]. *)

(* In [Up (a, b)], we require [a < b], so the sequence is nonempty. *)

type _ seq =
| Empty    : 'a seq
| Singleton: 'a -> 'a seq
| Rev      : index * 'a seq -> 'a seq
| Sum      : index * 'a seq * 'a seq -> 'a seq
| Product  : index * 'a seq * 'b seq -> ('a * 'b) seq
| Map      : index * ('a -> 'b) * 'a seq -> 'b seq
| Up       : int * int -> int seq

let is_empty (type a) (s : a seq) : bool =
  match s with
  | Empty ->
      true
  | Singleton _ ->
      false
  | Rev _ ->
      false
  | Sum _ ->
      false
  | Product _ ->
      false
  | Map _ ->
      false
  | Up _ ->
      false

let length (type a) (s : a seq) : index =
  match s with
  | Empty ->
      Z.zero
  | Singleton _ ->
      Z.one
  | Rev (length, _) ->
      length
  | Sum (length, _, _) ->
      length
  | Product (length, _, _) ->
      length
  | Map (length, _, _) ->
      length
  | Up (a, b) ->
      Z.of_int (b - a)

let out_of_bounds () =
  failwith "Index is out of bounds."

let empty =
  Empty

let zero =
  empty

let singleton x =
  Singleton x

let one =
  singleton

let rev (type a) (s : a seq) : a seq =
  match s with
  | Empty ->
      s
  | Singleton _ ->
      s
  | Rev (_, s) ->
      s
  | Sum _ ->
      Rev (length s, s)
  | Product _ ->
      Rev (length s, s)
  | Map _ ->
      Rev (length s, s)
  | Up _ ->
      Rev (length s, s)

let sum s1 s2 =
  if is_empty s1 then
    s2
  else if is_empty s2 then
    s1
  else
    let length = Z.add (length s1) (length s2) in
    Sum (length, s1, s2)

let ( ++ ) =
  sum

let product s1 s2 =
  if is_empty s1 || is_empty s2 then
    empty
  else
    let length = Z.mul (length s1) (length s2) in
    Product (length, s1, s2)

let ( ** ) =
  product

let map phi s =
  if is_empty s then
    empty
  else
    Map (length s, phi, s)

let up a b =
  if a < b then
    (* We might wish to also check that [b - a] does not overflow. *)
    Up (a, b)
  else
    Empty

let rec get : type a . a seq -> index -> a =
  fun s i ->
    match s with
    | Empty ->
        out_of_bounds()
    | Singleton x ->
        if Z.equal i Z.zero then x else out_of_bounds()
    | Rev (n, s) ->
        get s (Z.sub (Z.pred n) i)
    | Sum (_, s1, s2) ->
        let n1 = length s1 in
        if Z.lt i n1 then get s1 i
        else get s2 (Z.sub i n1)
    | Product (_, s1, s2) ->
        let q, r = Z.div_rem i (length s2) in
        get s1 q, get s2 r
    | Map (_, phi, s) ->
        phi (get s i)
    | Up (a, b) ->
        match Z.to_int i with
        | exception Z.Overflow ->
            out_of_bounds()
        | i ->
            let x = a + i in
            if x < a || b <= x then
              out_of_bounds()
            else
              x

let rec foreach : type a . a seq -> bool -> (a -> unit) -> unit =
  fun s sense k ->
    match s with
    | Empty ->
        ()
    | Singleton x ->
        k x
    | Rev (_, s) ->
        foreach s (not sense) k
    | Sum (_, s1, s2) ->
        let s1, s2 = if sense then s1, s2 else s2, s1 in
        foreach s1 sense k;
        foreach s2 sense k
    | Product (_, s1, s2) ->
        foreach s1 sense (fun x1 ->
          foreach s2 sense (fun x2 ->
            k (x1, x2)
          )
        )
    | Map (_, phi, s) ->
        foreach s sense (fun x -> k (phi x))
    | Up (a, b) ->
        if sense then
          for x = a to b - 1 do
            k x
          done
        else
          for x = b - 1 downto a do
            k x
          done

let foreach s f =
  foreach s true f

(* In order to avoid concatenation [Seq.concat] and flattening [Seq.flat_map],
   a producer of a sequence of type ['a Seq.t] must be parameterized over a
   construction function [cons] and a continuation [k]. Thus, a producer has
   a type of the following form: *)

type ('a, 'b) producer =
  ('a -> 'b Seq.t -> 'b Seq.t) -> 'b Seq.t -> 'b Seq.t

(* [interval sense a b] produces the sequence of integers between [a] included
   and [b] excluded. If [sense] is [true], this sequence is produced in
   ascending order; otherwise, it is produced in descending order. *)

let rec interval sense a b : (int, 'b) producer =
  fun cons k ->
    if a < b then
      (* Compute the first element [x] and the parameters [a] and [b]
         of the recursive call. *)
      let x, a, b = if sense then a, a+1, b else b-1, a, b-1 in
      (* Produce [x] and delay the recursive call. *)
      cons x (fun () -> interval sense a b cons k ())
    else
      k

(* [to_seq s sense] produces the sequence [s]. If [sense] is [true], then this
   sequence is produced in order; otherwise, it is produced in reverse order. *)

(* Parameterizing this definition with [cons] and [k] allows us to avoid using
   [Seq.concat] and [Seq.flat_map]. Without these parameters, the treatment of
   sums and products would require calls to these higher-order functions. *)

let rec to_seq : type a b . a seq -> bool -> (a, b) producer =
  fun s sense cons k ->
    match s with
    | Empty ->
        k
    | Singleton x ->
        cons x k
    | Rev (_, s) ->
        to_seq s (not sense) cons k
    | Sum (_, s1, s2) ->
        let s1, s2 = if sense then s1, s2 else s2, s1 in
        to_seq s1 sense cons (fun () -> to_seq s2 sense cons k ())
    | Product (_, s1, s2) ->
        to_seq s1 sense (fun x1 k ->
          to_seq s2 sense (fun x2 k ->
            cons (x1, x2) k
          ) k
        ) k
    | Map (_, phi, s) ->
        to_seq s sense (fun x k -> cons (phi x) k) k
    | Up (a, b) ->
        interval sense a b cons k

let cons x xs =
  fun () -> Seq.Cons (x, xs)

let to_seq s k =
  to_seq s true cons k

end
OCaml

Innovation. Community. Security.