• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

formalsec / smtml / 536

02 May 2026 03:27PM UTC coverage: 48.356% (+0.07%) from 48.287%
536

push

github

filipeom
Improve failure info in mappings

0 of 13 new or added lines in 2 files covered. (0.0%)

51 existing lines in 1 file now uncovered.

2426 of 5017 relevant lines covered (48.36%)

41.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.46
/src/smtml/mappings.ml
1
(* SPDX-License-Identifier: MIT *)
2
(* Copyright (C) 2023-2026 formalsec *)
3
(* Written by the Smtml programmers *)
4

5
include Mappings_intf
6

7
module Make (M_with_make : M_with_make) : S_with_fresh = struct
8
  module Mappings : M_with_make = M_with_make
9

10
  module Make_ (M : M) : S = struct
11
    open Ty
12
    module Smap = Symbol.Map
13

14
    type symbol_ctx = M.term Smap.t
15

16
    module Encoder = struct
17
      let i8 = M.Types.bitv 8
183✔
18

19
      let i32 = M.Types.bitv 32
183✔
20

21
      let i64 = M.Types.bitv 64
183✔
22

23
      let f32 = M.Types.float 8 24
183✔
24

25
      let f64 = M.Types.float 11 53
183✔
26

27
      let real2str =
28
        M.Func.make "real_to_string " [ M.Types.real ] M.Types.string
183✔
29

30
      let str2real =
31
        M.Func.make "string_to_real" [ M.Types.string ] M.Types.real
183✔
32

33
      let str_trim = M.Func.make "string_trim" [ M.Types.string ] M.Types.string
183✔
34

35
      let f32_to_i32 = M.Func.make "f32_to_i32" [ f32 ] i32
183✔
36

37
      let f64_to_i64 = M.Func.make "f64_to_i64" [ f64 ] i64
183✔
38

39
      let[@inline] get_type ty =
40
        match ty with
1,004✔
41
        | Ty_int -> M.Types.int
628✔
42
        | Ty_real -> M.Types.real
28✔
43
        | Ty_bool -> M.Types.bool
102✔
44
        | Ty_str -> M.Types.string
72✔
45
        | Ty_bitv 8 -> i8
4✔
46
        | Ty_bitv 32 -> i32
15✔
47
        | Ty_bitv 64 -> i64
1✔
48
        | Ty_bitv n -> M.Types.bitv n
65✔
49
        | Ty_fp 32 -> f32
60✔
50
        | Ty_fp 64 -> f64
29✔
51
        | Ty_roundingMode -> M.Types.roundingMode
×
52
        | Ty_regexp -> M.Types.regexp
×
53
        | (Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none) as ty ->
×
54
          Fmt.failwith "Trying to use unsupported theory: %a@." Ty.pp ty
55

56
      let make_symbol (ctx : symbol_ctx) (s : Symbol.t) : symbol_ctx * M.term =
57
        let name =
997✔
58
          match s.name with Simple name -> name | _ -> assert false
997✔
59
        in
60
        if M.Internals.caches_consts then
61
          let sym = M.const name (get_type s.ty) in
997✔
62
          (Smap.add s sym ctx, sym)
997✔
63
        else
64
          match Smap.find_opt s ctx with
×
65
          | Some sym -> (ctx, sym)
×
66
          | None ->
×
67
            let sym = M.const name (get_type s.ty) in
×
68
            (Smap.add s sym ctx, sym)
×
69

70
      module Bool_impl = struct
71
        let true_ = M.true_
72

73
        let false_ = M.false_
74

75
        let[@inline] unop op t =
76
          match op with
40✔
77
          | Unop.Not -> M.not_ t
40✔
78
          | op ->
×
79
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
80
              __FUNCTION__ Unop.pp op
81

82
        let binop op t1 t2 =
83
          match op with
129✔
84
          | Binop.And -> M.and_ t1 t2
87✔
85
          | Or -> M.or_ t1 t2
34✔
86
          | Xor -> M.xor t1 t2
6✔
87
          | Implies -> M.implies t1 t2
2✔
88
          | op ->
×
89
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
90
              __FUNCTION__ Binop.pp op
91

92
        let triop op t1 t2 t3 =
93
          match op with
6✔
94
          | Triop.Ite -> M.ite t1 t2 t3
6✔
95
          | op ->
×
96
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
97
              __FUNCTION__ Triop.pp op
98

99
        let relop op e1 e2 =
100
          match op with
135✔
101
          | Relop.Eq -> M.eq e1 e2
122✔
102
          | Ne -> M.distinct [ e1; e2 ]
13✔
103
          | _ ->
×
104
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
105
              __FUNCTION__ Relop.pp op
106

107
        let naryop op l =
108
          match op with
3✔
109
          | Naryop.Logand -> M.logand l
1✔
110
          | Logor -> M.logor l
×
111
          | Distinct -> M.distinct l
2✔
112
          | _ ->
×
113
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
114
              __FUNCTION__ Naryop.pp op
115

116
        let cvtop op _e =
NEW
117
          Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
×
118
            __FUNCTION__ Cvtop.pp op
119
      end
120

121
      module Int_impl = struct
122
        let v i = M.int i [@@inline]
510✔
123

124
        let unop op t =
125
          match op with
3✔
126
          | Unop.Neg -> M.Int.neg t
3✔
127
          | op ->
×
128
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
129
              __FUNCTION__ Unop.pp op
130

131
        let binop op t1 t2 =
132
          match op with
552✔
133
          | Binop.Add -> M.Int.add t1 t2
383✔
134
          | Sub -> M.Int.sub t1 t2
6✔
135
          | Mul -> M.Int.mul t1 t2
141✔
136
          | Div -> M.Int.div t1 t2
14✔
137
          | Rem -> M.Int.rem t1 t2
6✔
138
          | Pow -> M.Int.pow t1 t2
2✔
139
          | op ->
×
140
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
141
              __FUNCTION__ Binop.pp op
142

143
        let relop op t1 t2 =
144
          match op with
203✔
145
          | Relop.Eq -> M.eq t1 t2
1✔
146
          | Ne -> M.distinct [ t1; t2 ]
×
147
          | Lt -> M.Int.lt t1 t2
18✔
148
          | Le -> M.Int.le t1 t2
184✔
149
          | op ->
×
150
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
151
              __FUNCTION__ Relop.pp op
152

153
        let cvtop op e =
154
          match op with
×
155
          | Cvtop.Reinterpret_float -> M.Real.to_int e
×
156
          | op ->
×
157
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
158
              __FUNCTION__ Cvtop.pp op
159
      end
160

161
      module Real_impl = struct
162
        let v f = M.real f [@@inline]
6✔
163

164
        let unop op e =
165
          let open M in
×
166
          match op with
167
          | Unop.Neg -> Real.neg e
×
168
          | Abs -> ite (Real.gt e (real 0.)) e (Real.neg e)
×
169
          | Sqrt -> Real.pow e (v 0.5)
×
170
          | Ceil ->
×
171
            let x_int = M.Real.to_int e in
172
            ite (eq (Int.to_real x_int) e) x_int (Int.add x_int (int 1))
×
173
          | Floor -> Real.to_int e
×
174
          | Nearest | Is_nan | _ ->
×
175
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
176
              __FUNCTION__ Unop.pp op
177

178
        let binop op e1 e2 =
179
          match op with
6✔
180
          | Binop.Add -> M.Real.add e1 e2
×
181
          | Sub -> M.Real.sub e1 e2
×
182
          | Mul -> M.Real.mul e1 e2
6✔
183
          | Div -> M.Real.div e1 e2
×
184
          | Pow -> M.Real.pow e1 e2
×
185
          | Min -> M.ite (M.Real.le e1 e2) e1 e2
×
186
          | Max -> M.ite (M.Real.ge e1 e2) e1 e2
×
187
          | _ ->
×
188
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
189
              __FUNCTION__ Binop.pp op
190

191
        let relop op e1 e2 =
192
          match op with
×
193
          | Relop.Eq -> M.eq e1 e2
×
194
          | Ne -> M.distinct [ e1; e2 ]
×
195
          | Lt -> M.Real.lt e1 e2
×
196
          | Le -> M.Real.le e1 e2
×
197
          | _ ->
×
198
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
199
              __FUNCTION__ Relop.pp op
200

201
        let cvtop op e =
202
          match op with
2✔
203
          | Cvtop.ToString -> M.Func.apply real2str [ e ]
2✔
204
          | OfString -> M.Func.apply str2real [ e ]
×
205
          | Reinterpret_int -> M.Int.to_real e
×
206
          | op ->
×
207
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
208
              __FUNCTION__ Cvtop.pp op
209
      end
210

211
      module String_impl = struct
212
        let v s = M.String.v s [@@inline]
76✔
213

214
        let unop op e =
215
          match op with
8✔
216
          | Unop.Length -> M.String.length e
8✔
217
          | Trim -> M.Func.apply str_trim [ e ]
×
218
          | op ->
×
219
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
220
              __FUNCTION__ Unop.pp op
221

222
        let binop op e1 e2 =
223
          match op with
38✔
224
          | Binop.At -> M.String.at e1 ~pos:e2
12✔
225
          | String_contains -> M.String.contains e1 ~sub:e2
6✔
226
          | String_prefix -> M.String.is_prefix e1 ~prefix:e2
6✔
227
          | String_suffix -> M.String.is_suffix e1 ~suffix:e2
6✔
228
          | String_in_re -> M.String.in_re e1 e2
8✔
229
          | String_last_index -> M.String.last_index_of e1 ~sub:e2
×
230
          | _ ->
×
231
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
232
              __FUNCTION__ Binop.pp op
233

234
        let triop op e1 e2 e3 =
235
          match op with
18✔
236
          | Triop.String_extract -> M.String.sub e1 ~pos:e2 ~len:e3
6✔
237
          | String_index -> M.String.index_of e1 ~sub:e2 ~pos:e3
6✔
238
          | String_replace -> M.String.replace e1 ~pattern:e2 ~with_:e3
6✔
239
          | String_replace_all -> M.String.replace_all e1 ~pattern:e2 ~with_:e3
×
240
          | String_replace_re -> M.String.replace_re e1 ~pattern:e2 ~with_:e3
×
241
          | String_replace_re_all ->
×
242
            M.String.replace_re_all e1 ~pattern:e2 ~with_:e3
243
          | _ ->
×
244
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
245
              __FUNCTION__ Triop.pp op
246

247
        let relop op e1 e2 =
248
          match op with
8✔
249
          | Relop.Eq -> M.eq e1 e2
×
250
          | Ne -> M.distinct [ e1; e2 ]
×
251
          | Lt -> M.String.lt e1 e2
4✔
252
          | Le -> M.String.le e1 e2
4✔
253
          | _ ->
×
254
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
255
              __FUNCTION__ Relop.pp op
256

257
        let cvtop = function
258
          | Cvtop.String_to_code -> M.String.to_code
6✔
259
          | String_from_code -> M.String.of_code
×
260
          | String_to_int -> M.String.to_int
×
261
          | String_from_int -> M.String.of_int
×
262
          | String_to_re -> M.String.to_re
12✔
263
          | op ->
×
264
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
265
              __FUNCTION__ Cvtop.pp op
266

267
        let naryop op es =
268
          match op with
×
269
          | Naryop.Concat -> M.String.concat es
×
270
          | _ ->
×
271
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
272
              __FUNCTION__ Naryop.pp op
273
      end
274

275
      module Regexp_impl = struct
276
        let unop op e =
277
          match op with
2✔
278
          | Unop.Regexp_star -> M.Re.star e
2✔
279
          | Regexp_plus -> M.Re.plus e
×
280
          | Regexp_opt -> M.Re.opt e
×
281
          | Regexp_comp -> M.Re.comp e
×
282
          | Regexp_loop (min, max) -> M.Re.loop ~min ~max e
×
283
          | op ->
×
284
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
285
              __FUNCTION__ Unop.pp op
286

287
        let binop op e1 e2 =
288
          match op with
1✔
289
          | Binop.Regexp_range -> M.Re.range e1 e2
1✔
290
          | Regexp_inter -> M.Re.inter e1 e2
×
291
          | Regexp_diff -> M.Re.diff e1 e2
×
292
          | op ->
×
293
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
294
              __FUNCTION__ Binop.pp op
295

296
        let naryop op es =
297
          match op with
4✔
298
          | Naryop.Concat -> M.Re.concat es
2✔
299
          | Regexp_union -> M.Re.union es
2✔
300
          | op ->
×
301
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
302
              __FUNCTION__ Naryop.pp op
303
      end
304

305
      module Bitv_impl = struct
306
        open M
307

308
        let v bv = Bitv.of_z (Bitvector.to_signed bv) (Bitvector.numbits bv)
85✔
309

310
        (* Stolen from @krtab in OCamlPro/owi#195 *)
311
        let clz bitwidth n =
312
          let rec loop (lb : int) (ub : int) =
×
313
            if ub = lb + 1 then
×
314
              v @@ Bitvector.make (Z.of_int (bitwidth - ub)) bitwidth
×
315
            else
316
              let mid = (lb + ub) / 2 in
×
317
              let pow_two_mid =
318
                Bitvector.shl
319
                  (Bitvector.make Z.one bitwidth)
×
320
                  (Bitvector.make (Z.of_int mid) bitwidth)
×
321
              in
322
              ite (Bitv.lt_u n (v pow_two_mid)) (loop lb mid) (loop mid ub)
×
323
          in
324
          M.ite
325
            (M.eq n (v @@ Bitvector.make Z.zero bitwidth))
×
326
            (v @@ Bitvector.make (Z.of_int bitwidth) bitwidth)
×
327
            (loop 0 bitwidth)
×
328

329
        (* Stolen from @krtab in OCamlPro/owi #195 *)
330
        let ctz bitwidth n =
331
          let zero = v @@ Bitvector.make Z.zero bitwidth in
×
332
          let rec loop (lb : int) (ub : int) =
×
333
            if ub = lb + 1 then v (Bitvector.make (Z.of_int lb) bitwidth)
×
334
            else
335
              let mid = (lb + ub) / 2 in
×
336
              let pow_two_mid =
337
                Bitvector.shl
338
                  (Bitvector.make Z.one bitwidth)
×
339
                  (Bitvector.make (Z.of_int mid) bitwidth)
×
340
              in
341
              M.ite
×
342
                (eq (Bitv.rem n (v pow_two_mid)) zero)
×
343
                (loop mid ub) (loop lb mid)
×
344
          in
345
          ite (eq n zero)
×
346
            (v (Bitvector.make (Z.of_int bitwidth) bitwidth))
×
347
            (loop 0 bitwidth)
×
348

349
        let popcnt bitwidth n =
350
          let rec loop (next : int) count =
×
351
            if next = bitwidth then count
×
352
            else
353
              (* We shift the original number so that the current bit to test is on the right. *)
354
              let shifted =
×
355
                Bitv.lshr n (v @@ Bitvector.make (Z.of_int next) bitwidth)
×
356
              in
357
              (* We compute the remainder of the shifted number *)
358
              let remainder =
×
359
                Bitv.rem_u shifted (v @@ Bitvector.make (Z.of_int 2) bitwidth)
×
360
              in
361
              (* The remainder is either 0 or 1, we add it directly to the count *)
362
              let count = Bitv.add count remainder in
×
363
              let next = succ next in
×
364
              loop next count
×
365
          in
366
          loop 0 (v @@ Bitvector.make Z.zero bitwidth)
×
367

368
        let unop bitwidth op t =
369
          match op with
×
370
          | Unop.Clz -> clz bitwidth t
×
371
          | Ctz -> ctz bitwidth t
×
372
          | Popcnt -> popcnt bitwidth t
×
373
          | Neg -> Bitv.neg t
×
374
          | Not -> Bitv.lognot t
×
375
          | op ->
×
376
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
377
              __FUNCTION__ Unop.pp op
378

379
        let binop op t1 t2 =
380
          match op with
×
381
          | Binop.Add -> Bitv.add t1 t2
×
382
          | Sub -> Bitv.sub t1 t2
×
383
          | Mul -> Bitv.mul t1 t2
×
384
          | Div -> Bitv.div t1 t2
×
385
          | DivU -> Bitv.div_u t1 t2
×
386
          | And -> Bitv.logand t1 t2
×
387
          | Xor -> Bitv.logxor t1 t2
×
388
          | Or -> Bitv.logor t1 t2
×
389
          | Shl -> Bitv.shl t1 t2
×
390
          | ShrA -> Bitv.ashr t1 t2
×
391
          | ShrL -> Bitv.lshr t1 t2
×
392
          | Rem -> Bitv.rem t1 t2
×
393
          | RemU -> Bitv.rem_u t1 t2
×
394
          | Rotl -> Bitv.rotate_left t1 t2
×
395
          | Rotr -> Bitv.rotate_right t1 t2
×
396
          | op ->
×
397
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
398
              __FUNCTION__ Binop.pp op
399

400
        let triop op _ _ _ =
NEW
401
          Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
×
402
            __FUNCTION__ Triop.pp op
403

404
        let relop op e1 e2 =
405
          match op with
78✔
406
          | Relop.Eq -> M.eq e1 e2
71✔
407
          | Ne -> M.distinct [ e1; e2 ]
×
408
          | Lt -> Bitv.lt e1 e2
7✔
409
          | LtU -> Bitv.lt_u e1 e2
×
410
          | Le -> Bitv.le e1 e2
×
411
          | LeU -> Bitv.le_u e1 e2
×
412

413
        let to_ieee_bv bitwidth t =
414
          match M.Float.to_ieee_bv with
1✔
415
          | Some to_ieee_bv -> to_ieee_bv t
1✔
416
          | None ->
×
417
            begin match bitwidth with
418
            | 32 -> Func.apply f32_to_i32 [ t ]
×
419
            | 64 -> Func.apply f64_to_i64 [ t ]
×
420
            | _ ->
×
421
              Fmt.failwith "%s: unsupported bitwidth size of '%d'" __FUNCTION__
422
                bitwidth
423
            end
424

425
        let cvtop bitwidth op e =
426
          match op with
1✔
427
          | Cvtop.WrapI64 -> Bitv.extract e ~high:(bitwidth - 1) ~low:0
×
428
          | Sign_extend n -> Bitv.sign_extend n e
×
429
          | Zero_extend n -> Bitv.zero_extend n e
×
430
          | TruncSF32 | TruncSF64 | Trunc_sat_f32_s | Trunc_sat_f64_s ->
×
431
            Float.to_sbv bitwidth ~rm:Float.Rounding_mode.rtz e
432
          | TruncUF32 | TruncUF64 | Trunc_sat_f32_u | Trunc_sat_f64_u ->
×
433
            Float.to_ubv bitwidth ~rm:Float.Rounding_mode.rtz e
434
          | Reinterpret_float -> to_ieee_bv bitwidth e
1✔
435
          | ToBool -> M.distinct [ e; v @@ Bitvector.make Z.zero bitwidth ]
×
436
          | OfBool ->
×
437
            M.ite e
438
              (v @@ Bitvector.make Z.one bitwidth)
×
439
              (v @@ Bitvector.make Z.zero bitwidth)
×
440
          | _ ->
×
441
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
442
              __FUNCTION__ Cvtop.pp op
443
      end
444

445
      module type Float_sig = sig
446
        type elt
447

448
        val eb : int
449

450
        val sb : int
451

452
        val zero : unit -> M.term
453

454
        val v : elt -> M.term
455
        (* TODO: *)
456
        (* val to_string : Z3.FuncDecl.func_decl *)
457
        (* val of_string : Z3.FuncDecl.func_decl *)
458
      end
459

460
      module Float_impl (F : Float_sig) = struct
461
        open M
462
        include F
463

464
        let unop op e =
465
          match op with
18✔
466
          | Unop.Neg -> Float.neg e
×
467
          | Abs -> Float.abs e
1✔
468
          | Sqrt -> Float.sqrt ~rm:Float.Rounding_mode.rne e
1✔
469
          | Is_normal -> Float.is_normal e
×
470
          | Is_subnormal -> Float.is_subnormal e
×
471
          | Is_negative -> Float.is_negative e
×
472
          | Is_positive -> Float.is_positive e
×
473
          | Is_infinite -> Float.is_infinite e
×
474
          | Is_nan -> Float.is_nan e
4✔
475
          | Is_zero -> Float.is_zero e
×
476
          | Ceil -> Float.round_to_integral ~rm:Float.Rounding_mode.rtp e
4✔
477
          | Floor -> Float.round_to_integral ~rm:Float.Rounding_mode.rtn e
4✔
478
          | Trunc -> Float.round_to_integral ~rm:Float.Rounding_mode.rtz e
4✔
479
          | Nearest -> Float.round_to_integral ~rm:Float.Rounding_mode.rne e
×
480
          | _ ->
×
481
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
482
              __FUNCTION__ Unop.pp op
483

484
        let binop op e1 e2 =
485
          match op with
13✔
486
          | Binop.Add -> Float.add ~rm:Float.Rounding_mode.rne e1 e2
4✔
487
          | Sub -> Float.sub ~rm:Float.Rounding_mode.rne e1 e2
2✔
488
          | Mul -> Float.mul ~rm:Float.Rounding_mode.rne e1 e2
×
489
          | Div -> Float.div ~rm:Float.Rounding_mode.rne e1 e2
3✔
490
          | Min -> Float.min e1 e2
×
491
          | Max -> Float.max e1 e2
2✔
492
          | Rem -> Float.rem e1 e2
×
493
          | Copysign ->
2✔
494
            let abs_float = Float.abs e1 in
495
            M.ite (Float.ge e2 (F.zero ())) abs_float (Float.neg abs_float)
2✔
496
          | _ ->
×
497
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
498
              __FUNCTION__ Binop.pp op
499

500
        let triop op _ _ _ =
NEW
501
          Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
×
502
            __FUNCTION__ Triop.pp op
503

504
        let relop op e1 e2 =
505
          match op with
35✔
506
          | Relop.Eq -> Float.eq e1 e2
26✔
507
          | Ne -> not_ @@ Float.eq e1 e2
1✔
508
          | Lt -> Float.lt e1 e2
8✔
509
          | Le -> Float.le e1 e2
×
510
          | _ ->
×
511
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
512
              __FUNCTION__ Relop.pp op
513

514
        let cvtop op e =
515
          match op with
×
516
          | Cvtop.PromoteF32 | DemoteF64 ->
×
517
            Float.to_fp eb sb ~rm:Float.Rounding_mode.rne e
518
          | ConvertSI32 | ConvertSI64 ->
×
519
            Float.sbv_to_fp eb sb ~rm:Float.Rounding_mode.rne e
520
          | ConvertUI32 | ConvertUI64 ->
×
521
            Float.ubv_to_fp eb sb ~rm:Float.Rounding_mode.rne e
522
          | Reinterpret_int -> Float.of_ieee_bv eb sb e
×
523
          | ToString ->
×
524
            (* TODO: FuncDecl.apply to_string [ e ] *)
525
            Fmt.failwith {|%s: Unsupported operator "ToString"|} __MODULE__
526
          | OfString ->
×
527
            (* TODO: FuncDecl.apply of_string [ e ] *)
528
            Fmt.failwith {|%s: Unsupported operator "OfString"|} __MODULE__
529
          | _ ->
×
530
            Fmt.failwith {|%s: Unsupported %s operator "%a"|} __MODULE__
531
              __FUNCTION__ Cvtop.pp op
532
      end
533

534
      module Float32_impl = Float_impl (struct
535
        type elt = int32
536

537
        let eb = 8
538

539
        let sb = 24
540

541
        let v f = M.Float.v (Int32.float_of_bits f) eb sb
29✔
542

543
        let zero () = v (Int32.bits_of_float 0.0)
1✔
544

545
        (* TODO: *)
546
        (* let to_string = *)
547
        (*   Z3.FuncDecl.mk_func_decl_s ctx "F32ToString" [ fp32_sort ] str_sort *)
548
        (* let of_string = *)
549
        (*   Z3.FuncDecl.mk_func_decl_s ctx "StringToF32" [ str_sort ] fp32_sort *)
550
      end)
551

552
      module Float64_impl = Float_impl (struct
553
        type elt = int64
554

555
        let eb = 11
556

557
        let sb = 53
558

559
        let v f = M.Float.v (Int64.float_of_bits f) eb sb
15✔
560

561
        let zero () = v (Int64.bits_of_float 0.0)
1✔
562

563
        (* TODO: *)
564
        (* let to_string = *)
565
        (*   Z3.FuncDecl.mk_func_decl_s ctx "F64ToString" [ fp64_sort ] str_sort *)
566
        (* let of_string = *)
567
        (*   Z3.FuncDecl.mk_func_decl_s ctx "StringToF64" [ str_sort ] fp64_sort *)
568
      end)
569

570
      let v (value : Value.t) : M.term =
571
        match value with
773✔
572
        | True -> Bool_impl.true_
37✔
573
        | False -> Bool_impl.false_
16✔
574
        | Int v -> Int_impl.v v
510✔
575
        | Real v -> Real_impl.v v
6✔
576
        | Str v -> String_impl.v v
76✔
577
        | Num (F32 x) -> Float32_impl.v x
28✔
578
        | Num (F64 x) -> Float64_impl.v x
14✔
579
        | Bitv bv -> Bitv_impl.v bv
85✔
580
        | Re_none -> M.Re.none ()
1✔
581
        | Re_all -> M.Re.all ()
×
582
        | Re_allchar -> M.Re.allchar ()
×
583
        | List _ | App _ | Unit | Nothing ->
×
584
          Fmt.failwith "Unsupported encoding of value '%a'" Value.pp value
585

586
      let unop ty op t =
587
        match ty with
71✔
588
        | Ty.Ty_int -> Int_impl.unop op t
3✔
589
        | Ty_real -> Real_impl.unop op t
×
590
        | Ty_bool -> Bool_impl.unop op t
40✔
591
        | Ty_str -> String_impl.unop op t
8✔
592
        | Ty_regexp -> Regexp_impl.unop op t
2✔
593
        | Ty_bitv bitwidth -> Bitv_impl.unop bitwidth op t
×
594
        | Ty_fp 32 -> Float32_impl.unop op t
17✔
595
        | Ty_fp 64 -> Float64_impl.unop op t
1✔
596
        | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none | Ty_roundingMode ->
×
597
          Fmt.failwith "Unsupported encoding of unary operators for theory '%a'"
598
            Ty.pp ty
599

600
      let binop ty op t1 t2 =
601
        match ty with
739✔
602
        | Ty.Ty_int -> Int_impl.binop op t1 t2
552✔
603
        | Ty_real -> Real_impl.binop op t1 t2
6✔
604
        | Ty_bool -> Bool_impl.binop op t1 t2
129✔
605
        | Ty_str -> String_impl.binop op t1 t2
38✔
606
        | Ty_regexp -> Regexp_impl.binop op t1 t2
1✔
607
        | Ty_bitv _bitwidth -> Bitv_impl.binop op t1 t2
×
608
        | Ty_fp 32 -> Float32_impl.binop op t1 t2
8✔
609
        | Ty_fp 64 -> Float64_impl.binop op t1 t2
5✔
610
        | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none | Ty_roundingMode ->
×
611
          Fmt.failwith
612
            "Unsupported encoding of binary operators for theory '%a'" Ty.pp ty
613

614
      let triop ty op t1 t2 t3 =
615
        match ty with
24✔
616
        | Ty.Ty_bool -> Bool_impl.triop op t1 t2 t3
6✔
617
        | Ty_str -> String_impl.triop op t1 t2 t3
18✔
618
        | Ty_bitv _bitwidth -> Bitv_impl.triop op t1 t2 t3
×
619
        | Ty_fp 32 -> Float32_impl.triop op t1 t2 t3
×
620
        | Ty_fp 64 -> Float64_impl.triop op t1 t2 t3
×
621
        | Ty_int | Ty_real | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none
×
622
        | Ty_regexp | Ty_roundingMode ->
×
623
          Fmt.failwith
624
            "Unsupported encoding of ternary operators for theory '%a'" Ty.pp ty
625

626
      let relop ty op t1 t2 =
627
        match ty with
459✔
628
        | Ty.Ty_int -> Int_impl.relop op t1 t2
203✔
629
        | Ty_real -> Real_impl.relop op t1 t2
×
630
        | Ty_bool -> Bool_impl.relop op t1 t2
135✔
631
        | Ty_str -> String_impl.relop op t1 t2
8✔
632
        | Ty_bitv _bitwidth -> Bitv_impl.relop op t1 t2
78✔
633
        | Ty_fp 32 -> Float32_impl.relop op t1 t2
25✔
634
        | Ty_fp 64 -> Float64_impl.relop op t1 t2
10✔
635
        | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none | Ty_regexp
×
636
        | Ty_roundingMode ->
×
637
          Fmt.failwith "Unsupported encoding of relop operators for theory '%a'"
638
            Ty.pp ty
639

640
      let cvtop ty op t =
641
        match ty with
21✔
642
        | Ty.Ty_int -> Int_impl.cvtop op t
×
643
        | Ty_real -> Real_impl.cvtop op t
2✔
644
        | Ty_bool -> Bool_impl.cvtop op t
×
645
        | Ty_str -> String_impl.cvtop op t
18✔
646
        | Ty_bitv bitwidth -> Bitv_impl.cvtop bitwidth op t
1✔
647
        | Ty_fp 32 -> Float32_impl.cvtop op t
×
648
        | Ty_fp 64 -> Float64_impl.cvtop op t
×
649
        | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none | Ty_regexp
×
650
        | Ty_roundingMode ->
×
651
          Fmt.failwith
652
            "Unsupported encoding of convert operators for theory '%a'" Ty.pp ty
653

654
      let naryop ty op ts =
655
        match ty with
7✔
656
        | Ty.Ty_str -> String_impl.naryop op ts
×
657
        | Ty_bool -> Bool_impl.naryop op ts
3✔
658
        | Ty_regexp -> Regexp_impl.naryop op ts
4✔
659
        | ty ->
×
660
          Fmt.failwith "Unsupported encoding of n-ary operators for theory '%a'"
661
            Ty.pp ty ty
662

663
      let get_rounding_mode ctx rm =
664
        match Expr.view rm with
×
665
        | Symbol { name = Simple ("roundNearestTiesToEven" | "RNE"); _ } ->
×
666
          (ctx, M.Float.Rounding_mode.rne)
667
        | Symbol { name = Simple ("roundNearestTiesToAway" | "RNA"); _ } ->
×
668
          (ctx, M.Float.Rounding_mode.rna)
669
        | Symbol { name = Simple ("roundTowardPositive" | "RTP"); _ } ->
×
670
          (ctx, M.Float.Rounding_mode.rtp)
671
        | Symbol { name = Simple ("roundTowardNegative" | "RTN"); _ } ->
×
672
          (ctx, M.Float.Rounding_mode.rtn)
673
        | Symbol { name = Simple ("roundTowardZero" | "RTZ"); _ } ->
×
674
          (ctx, M.Float.Rounding_mode.rtz)
675
        | Symbol rm -> make_symbol ctx rm
×
676
        | _ -> Fmt.failwith "unknown rouding mode: %a" Expr.pp rm
×
677

678
      let rec encode_expr ctx (hte : Expr.t) : symbol_ctx * M.term =
679
        match Expr.view hte with
3,105✔
680
        | Val value -> (ctx, v value)
773✔
681
        | Ptr { base; offset } ->
×
682
          let base = v (Bitv base) in
683
          let ctx, offset = encode_expr ctx offset in
×
684
          (ctx, binop (Ty_bitv 32) Add base offset)
×
685
        | Symbol { name = Simple "re.all"; _ } -> (ctx, M.Re.all ())
×
686
        | Symbol { name = Simple "re.none"; _ } -> (ctx, M.Re.none ())
×
687
        | Symbol { name = Simple "re.allchar"; _ } -> (ctx, M.Re.allchar ())
×
688
        | Symbol sym -> make_symbol ctx sym
997✔
689
        (* FIXME: add a way to support building these expressions without apps *)
690
        | App ({ name = Simple "fp.add"; _ }, [ rm; a; b ]) ->
×
691
          let ctx, a = encode_expr ctx a in
692
          let ctx, b = encode_expr ctx b in
×
693
          let ctx, rm = get_rounding_mode ctx rm in
×
694
          (ctx, M.Float.add ~rm a b)
×
695
        | App ({ name = Simple "fp.sub"; _ }, [ rm; a; b ]) ->
×
696
          let ctx, a = encode_expr ctx a in
697
          let ctx, b = encode_expr ctx b in
×
698
          let ctx, rm = get_rounding_mode ctx rm in
×
699
          (ctx, M.Float.sub ~rm a b)
×
700
        | App ({ name = Simple "fp.mul"; _ }, [ rm; a; b ]) ->
×
701
          let ctx, a = encode_expr ctx a in
702
          let ctx, b = encode_expr ctx b in
×
703
          let ctx, rm = get_rounding_mode ctx rm in
×
704
          (ctx, M.Float.mul ~rm a b)
×
705
        | App ({ name = Simple "fp.div"; _ }, [ rm; a; b ]) ->
×
706
          let ctx, a = encode_expr ctx a in
707
          let ctx, b = encode_expr ctx b in
×
708
          let ctx, rm = get_rounding_mode ctx rm in
×
709
          (ctx, M.Float.div ~rm a b)
×
710
        | App ({ name = Simple "fp.fma"; _ }, [ rm; a; b; c ]) ->
×
711
          let ctx, a = encode_expr ctx a in
712
          let ctx, b = encode_expr ctx b in
×
713
          let ctx, c = encode_expr ctx c in
×
714
          let ctx, rm = get_rounding_mode ctx rm in
×
715
          (ctx, M.Float.fma ~rm a b c)
×
716
        | App ({ name = Simple "fp.sqrt"; _ }, [ rm; a ]) ->
×
717
          let ctx, a = encode_expr ctx a in
718
          let ctx, rm = get_rounding_mode ctx rm in
×
719
          (ctx, M.Float.sqrt ~rm a)
×
720
        | App ({ name = Simple "fp.roundToIntegral"; _ }, [ rm; a ]) ->
×
721
          let ctx, a = encode_expr ctx a in
722
          let ctx, rm = get_rounding_mode ctx rm in
×
723
          (ctx, M.Float.round_to_integral ~rm a)
×
724
        | App (sym, args) ->
3✔
725
          let name =
726
            match Symbol.name sym with
727
            | Simple name -> name
3✔
728
            | Indexed _ ->
×
729
              Fmt.failwith "Unsupported uninterpreted application of: %a"
×
730
                Symbol.pp sym
731
          in
732
          let ty = get_type @@ Symbol.type_of sym in
3✔
733
          let tys = List.map (fun e -> get_type @@ Expr.ty e) args in
3✔
734
          let ctx, arguments = encode_exprs ctx args in
3✔
735
          let sym = M.Func.make name tys ty in
3✔
736
          (ctx, M.Func.apply sym arguments)
3✔
737
        | Unop (ty, op, e) ->
71✔
738
          let ctx, e = encode_expr ctx e in
739
          (ctx, unop ty op e)
71✔
740
        | Binop (ty, op, e1, e2) ->
739✔
741
          let ctx, e1 = encode_expr ctx e1 in
742
          let ctx, e2 = encode_expr ctx e2 in
739✔
743
          (ctx, binop ty op e1 e2)
739✔
744
        | Triop (ty, op, e1, e2, e3) ->
24✔
745
          let ctx, e1 = encode_expr ctx e1 in
746
          let ctx, e2 = encode_expr ctx e2 in
24✔
747
          let ctx, e3 = encode_expr ctx e3 in
24✔
748
          (ctx, triop ty op e1 e2 e3)
24✔
749
        | Relop (ty, op, e1, e2) ->
459✔
750
          let ctx, e1 = encode_expr ctx e1 in
751
          let ctx, e2 = encode_expr ctx e2 in
459✔
752
          (ctx, relop ty op e1 e2)
459✔
753
        | Cvtop (ty, op, e) ->
21✔
754
          let ctx, e = encode_expr ctx e in
755
          (ctx, cvtop ty op e)
21✔
756
        | Naryop (ty, op, es) ->
7✔
757
          let ctx, es =
758
            List.fold_left
759
              (fun (ctx, es) e ->
760
                let ctx, e = encode_expr ctx e in
19✔
761
                (ctx, e :: es) )
19✔
762
              (ctx, []) es
763
          in
764
          (* This is needed so arguments don't end up out of order in the operator *)
765
          let es = List.rev es in
7✔
766
          (ctx, naryop ty op es)
7✔
767
        | Extract (e, high, low) ->
6✔
768
          let ctx, e = encode_expr ctx e in
769
          (ctx, M.Bitv.extract e ~high ~low)
6✔
770
        | Concat (e1, e2) ->
2✔
771
          let ctx, e1 = encode_expr ctx e1 in
772
          let ctx, e2 = encode_expr ctx e2 in
2✔
773
          (ctx, M.Bitv.concat e1 e2)
2✔
774
        | Binder (Forall, vars, body) ->
2✔
775
          let ctx, vars = encode_exprs ctx vars in
776
          let ctx, body = encode_expr ctx body in
2✔
777
          (ctx, M.forall vars body)
2✔
778
        | Binder (Exists, vars, body) ->
1✔
779
          let ctx, vars = encode_exprs ctx vars in
780
          let ctx, body = encode_expr ctx body in
1✔
781
          (ctx, M.exists vars body)
1✔
782
        | List _ | Binder _ ->
×
783
          Fmt.failwith "Cannot encode expression: %a" Expr.pp hte
784

785
      and encode_exprs ctx (es : Expr.t list) : symbol_ctx * M.term list =
786
        let ctx, exprs =
239✔
787
          List.fold_left
788
            (fun (ctx, es) e ->
789
              let ctx, e = encode_expr ctx e in
478✔
790
              (ctx, e :: es) )
478✔
791
            (ctx, []) es
792
        in
793
        (ctx, List.rev exprs)
239✔
794

795
      let value_of_term ?ctx model ty term =
796
        let v =
74✔
797
          match M.Model.eval ?ctx ~completion:true model term with
798
          | Some v -> v
74✔
799
          | None -> Fmt.failwith "value_of_term: unable to fetch solver value"
×
800
        in
801
        match ty with
802
        | Ty_int -> Value.Int (M.Interp.to_int v)
19✔
803
        | Ty_real -> Value.Real (M.Interp.to_real v)
6✔
804
        | Ty_bool -> if M.Interp.to_bool v then Value.True else Value.False
3✔
805
        | Ty_str ->
10✔
806
          let str = M.Interp.to_string v in
807
          Value.Str str
10✔
808
        | Ty_bitv 1 ->
×
809
          let b = M.Interp.to_bitv v 1 in
810
          if Z.equal b Z.one then Value.True
×
811
          else (
×
812
            assert (Z.equal b Z.zero);
×
813
            Value.False )
814
        | Ty_bitv m -> Value.Bitv (Bitvector.make (M.Interp.to_bitv v m) m)
7✔
815
        | Ty_fp 32 ->
16✔
816
          let float = M.Interp.to_float v 8 24 in
817
          Value.Num (F32 (Int32.bits_of_float float))
16✔
818
        | Ty_fp 64 ->
4✔
819
          let float = M.Interp.to_float v 11 53 in
820
          Value.Num (F64 (Int64.bits_of_float float))
4✔
821
        | Ty_fp _ | Ty_list | Ty_app | Ty_unit | Ty_none | Ty_regexp
×
822
        | Ty_roundingMode ->
×
823
          Fmt.failwith
824
            "value_of_term: unsupported model completion for theory '%a'" Ty.pp
825
            ty
826
    end
827

828
    type model =
829
      { model : M.model
830
      ; ctx : symbol_ctx
831
      }
832

833
    type solver =
834
      { solver : M.solver
835
      ; ctx : symbol_ctx Stack.t
836
      ; mutable last_ctx :
837
          symbol_ctx option (* Used to save last check-sat ctx *)
838
      ; mutable assumptions :
839
          Expr.t list (* Assumptions added before the last `check_sat` *)
840
      ; mutable unchecked_assumptions :
841
          Expr.t list (* Assumptions added after the last `check_sat` *)
842
      ; mutable last_assumptions : Expr.t list
843
          (* Assumptions from the last `check_sat` *)
844
      }
845

846
    type handle = M.handle
847

848
    type optimize =
849
      { opt : M.optimizer
850
      ; ctx : symbol_ctx Stack.t
851
      }
852

853
    let value ({ model = m; ctx } : model) (c : Expr.t) : Value.t =
854
      let ctx, e = Encoder.encode_expr ctx c in
21✔
855
      Encoder.value_of_term ~ctx m (Expr.ty c) e
21✔
856

857
    let values_of_model ?symbols ({ model; ctx } as model0) =
858
      let m = Hashtbl.create 512 in
24✔
859
      ( match symbols with
24✔
860
      | Some symbols ->
1✔
861
        List.iter
1✔
862
          (fun sym ->
863
            let v = value model0 (Expr.symbol sym) in
1✔
864
            Hashtbl.add m sym v )
1✔
865
          symbols
866
      | None ->
23✔
867
        Smap.iter
23✔
868
          (fun (sym : Symbol.t) term ->
869
            let v = Encoder.value_of_term ~ctx model sym.ty term in
53✔
870
            Hashtbl.add m sym v )
53✔
871
          ctx );
872
      m
873

874
    let set_debug _ = ()
28✔
875

876
    module Smtlib = struct
877
      let pp ?name ?logic ?status fmt htes =
878
        (* FIXME: I don't know if encoding with the empty map is ok :\ *)
879
        let _, terms = Encoder.encode_exprs Smap.empty htes in
×
880
        M.Smtlib.pp ?name ?logic ?status fmt terms
×
881
    end
882

883
    module Solver = struct
884
      let make ?params ?logic () =
885
        let ctx = Stack.create () in
60✔
886
        Stack.push Smap.empty ctx;
60✔
887
        { solver = M.Solver.make ?params ?logic ()
59✔
888
        ; ctx
889
        ; last_ctx = None
890
        ; assumptions = []
891
        ; unchecked_assumptions = []
892
        ; last_assumptions = []
893
        }
894

895
      let clone
896
        { solver
897
        ; ctx
898
        ; last_ctx
899
        ; assumptions
900
        ; unchecked_assumptions
901
        ; last_assumptions
902
        } =
903
        { solver = M.Solver.clone solver
×
904
        ; ctx = Stack.copy ctx
×
905
        ; last_ctx
906
        ; assumptions
907
        ; unchecked_assumptions
908
        ; last_assumptions
909
        }
910

911
      let push { solver; ctx; _ } =
912
        match Stack.top_opt ctx with
40✔
913
        | None -> Fmt.failwith "Solver.push: invalid solver stack state"
×
914
        | Some top ->
40✔
915
          Stack.push top ctx;
916
          M.Solver.push solver
40✔
917

918
      let pop { solver; ctx; _ } n =
919
        match Stack.pop_opt ctx with
14✔
920
        | None -> Fmt.failwith "Solver.pop: stack is empty"
×
921
        | Some _ -> M.Solver.pop solver n
14✔
922

923
      let reset (s : solver) =
924
        Stack.clear s.ctx;
1✔
925
        Stack.push Smap.empty s.ctx;
1✔
926
        s.last_ctx <- None;
1✔
927
        s.assumptions <- [];
928
        s.unchecked_assumptions <- [];
929
        s.last_assumptions <- [];
930
        M.Solver.reset s.solver
931

932
      let add (s : solver) (exprs : Expr.t list) =
933
        match Stack.pop_opt s.ctx with
105✔
934
        | None -> Fmt.failwith "Solver.add: current solver context not found"
×
935
        | Some ctx ->
105✔
936
          if Option.is_some Utils.query_log_path then
937
            s.unchecked_assumptions <-
×
938
              List.rev_append exprs s.unchecked_assumptions;
×
939
          let ctx, exprs = Encoder.encode_exprs ctx exprs in
105✔
940
          Stack.push ctx s.ctx;
105✔
941
          M.Solver.add s.solver ~ctx exprs
105✔
942

943
      let check (s : solver) ~assumptions =
944
        match Stack.top_opt s.ctx with
91✔
945
        | None -> Fmt.failwith "Solver.check: invalid solver stack state"
×
946
        | Some ctx ->
91✔
947
          if Option.is_some Utils.query_log_path then (
×
948
            s.assumptions <- s.unchecked_assumptions @ s.assumptions;
949
            s.unchecked_assumptions <- [];
950
            s.last_assumptions <- assumptions );
951
          let ctx, encoded_assuptions = Encoder.encode_exprs ctx assumptions in
91✔
952
          s.last_ctx <- Some ctx;
91✔
953
          Utils.check_log_query
954
            (fun () ->
955
              M.Solver.check s.solver ~ctx ~assumptions:encoded_assuptions )
91✔
956
            M.Internals.name (List.rev assumptions)
91✔
957

958
      let model { solver; last_ctx; assumptions; last_assumptions; _ } =
959
        match last_ctx with
30✔
960
        | Some ctx ->
30✔
961
          Utils.model_log_query
962
            (fun () ->
963
              M.Solver.model solver |> Option.map (fun m -> { model = m; ctx }) )
30✔
964
            M.Internals.name
965
            (List.rev_append assumptions (List.rev last_assumptions))
30✔
966
        | None ->
×
967
          Fmt.failwith "model: Trying to fetch model before check-sat call"
968

969
      let add_simplifier s =
970
        { s with solver = M.Solver.add_simplifier s.solver }
×
971

972
      let interrupt _ = M.Solver.interrupt ()
×
973

974
      let was_interrupted _ = !M.Internals.was_interrupted
×
975

976
      let get_statistics { solver; _ } = M.Solver.get_statistics solver
3✔
977
    end
978

979
    module Optimizer = struct
980
      let make () =
981
        let ctx = Stack.create () in
13✔
982
        Stack.push Smap.empty ctx;
13✔
983
        { opt = M.Optimizer.make (); ctx }
13✔
984

985
      let push { opt; _ } = M.Optimizer.push opt
1✔
986

987
      let pop { opt; _ } = M.Optimizer.pop opt
1✔
988

989
      let add (o : optimize) exprs =
990
        match Stack.pop_opt o.ctx with
37✔
NEW
991
        | None ->
×
992
          Fmt.failwith "%s.%s: current solver context not found" __MODULE__
993
            __FUNCTION__
994
        | Some ctx ->
37✔
995
          let ctx, exprs = Encoder.encode_exprs ctx exprs in
996
          Stack.push ctx o.ctx;
37✔
997
          M.Optimizer.add o.opt exprs
37✔
998

999
      let check { opt; _ } = M.Optimizer.check opt
14✔
1000

1001
      let model { opt; ctx } =
1002
        match Stack.top_opt ctx with
14✔
NEW
1003
        | None ->
×
1004
          Fmt.failwith "%s.%s: current solver context not found" __MODULE__
1005
            __FUNCTION__
1006
        | Some ctx ->
14✔
1007
          M.Optimizer.model opt |> Option.map (fun m -> { model = m; ctx })
14✔
1008

1009
      let maximize (o : optimize) (expr : Expr.t) =
1010
        match Stack.pop_opt o.ctx with
13✔
NEW
1011
        | None ->
×
1012
          Fmt.failwith "%s.%s: current solver context not found" __MODULE__
1013
            __FUNCTION__
1014
        | Some ctx ->
13✔
1015
          let ctx, expr = Encoder.encode_expr ctx expr in
1016
          Stack.push ctx o.ctx;
13✔
1017
          M.Optimizer.maximize o.opt expr
13✔
1018

1019
      let minimize (o : optimize) (expr : Expr.t) =
1020
        match Stack.pop_opt o.ctx with
1✔
NEW
1021
        | None ->
×
1022
          Fmt.failwith "%s.%s: current solver context not found" __MODULE__
1023
            __FUNCTION__
1024
        | Some ctx ->
1✔
1025
          let ctx, expr = Encoder.encode_expr ctx expr in
1026
          Stack.push ctx o.ctx;
1✔
1027
          M.Optimizer.minimize o.opt expr
1✔
1028

1029
      let interrupt _ = M.Optimizer.interrupt ()
×
1030

1031
      let get_statistics { opt; _ } = M.Optimizer.get_statistics opt
×
1032
    end
1033
  end
1034

1035
  module Fresh = struct
1036
    module Make () = Make_ (M_with_make.Make ())
1037
  end
1038

1039
  let is_available = M_with_make.is_available
1040

1041
  include Make_ (M_with_make)
1042
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc