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
open Containers
type t = Atom.t Array.t
let of_list1 xs =
assert (not @@ List.is_empty xs);
Array.of_list xs
let tuple1 at = of_list1 [ at ]
let arity tuple =
let ar = Array.length tuple in
assert (ar > 0);
ar
let hash tuple = Hash.array Atom.hash tuple
let pp out atoms =
let open Fmtc in
(array ~sep:sp Atom.pp |> if arity atoms > 1 then parens else fun x -> x)
out
atoms
module P = Intf.Print.Mixin (struct
type nonrec t = t
let pp = pp
end)
include P
let to_list t = Array.to_list t
let compare t1 t2 = Array.compare Atom.compare t1 t2
let equal t1 t2 = Array.equal Atom.equal t1 t2
let transpose tuple =
assert (arity tuple = 2);
Array.rev tuple
let ith i tuple =
assert (i >= 0 && i < arity tuple);
tuple.(i)
let ( @@@ ) t1 t2 = Array.append t1 t2
let concat = function
| [] ->
invalid_arg "Tuple.concat: empty list of tuples"
| hd :: tl ->
List.fold_left ( @@@ ) hd tl
let join tuple1 tuple2 =
let t1 = tuple1 in
let t2 = tuple2 in
let lg1 = Array.length t1 in
let lg2 = Array.length t2 in
assert (Atom.equal (ith (arity tuple1 - 1) tuple1) (ith 0 tuple2));
let res = Array.make (lg1 + lg2 - 2) t1.(0) in
Array.blit t1 0 res 0 (lg1 - 1);
Array.blit t2 1 res (lg1 - 1) (lg2 - 1);
res
let is_in_join tup t1 t2 =
let lg1 = Array.length t1 in
assert (lg1 > 0);
assert (Array.length t2 > 0);
Atom.equal t1.(lg1 - 1) t2.(0) && (equal tup @@ join t1 t2)
let split tuple len =
let t = tuple in
let full_len = Array.length t in
assert (len > 0 && len < full_len);
let t1 = Array_slice.(make t 0 ~len |> copy) in
let t2 = Array_slice.(make t len ~len:(full_len - len) |> copy) in
(t1, t2)
let all_different t =
let sorted = Array.sorted Atom.compare t in
let lg = Array.length t in
assert (lg > 0);
let i = ref 1 in
let yes = ref true in
while !yes && !i < lg do
yes := Atom.compare sorted.(!i - 1) sorted.(!i) <> 0
done;
!yes
let to_1tuples t =
assert (Array.length t > 0);
Array.fold_right (fun at acc -> of_list1 [ at ] :: acc) t []
let to_ntuples n t =
let lg = Array.length t in
assert (lg > 0);
if lg mod n <> 0
then
invalid_arg
@@ Fmt.strf "Tuple.to_ntuples %d %a: length not a multiple of %d" n pp t n;
Array.to_list t |> List.sublists_of_len n |> List.map of_list1
let rename atom_renaming t =
Array.map (fun at -> List.assoc ~eq:Atom.equal at atom_renaming) t
module Set = CCSet.Make (struct
type nonrec t = t
let compare = compare
end)