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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# 1 "src/z3_mappings.default.ml"
(* SPDX-License-Identifier: MIT *)
(* Copyright (C) 2023-2024 formalsec *)
(* Written by the Smtml programmers *)

include Mappings_intf

module M = struct
  module Make () = struct
    type ty = Z3.Sort.sort

    type term = Z3.Expr.expr

    type interp = term

    type model = Z3.Model.model

    type solver = Z3.Solver.solver

    type handle = Z3.Optimize.handle

    type optimizer = Z3.Optimize.optimize

    type func_decl = Z3.FuncDecl.func_decl

    let caches_consts = true

    let ctx = Z3.mk_context []

    let true_ = Z3.Boolean.mk_true ctx

    let false_ = Z3.Boolean.mk_false ctx

    let int i = Z3.Arithmetic.Integer.mk_numeral_i ctx i

    let real f = Z3.Arithmetic.Real.mk_numeral_s ctx (Float.to_string f)

    let const sym ty = Z3.Expr.mk_const_s ctx sym ty

    let not_ e = Z3.Boolean.mk_not ctx e

    let and_ e1 e2 = Z3.Boolean.mk_and ctx [ e1; e2 ]

    let or_ e1 e2 = Z3.Boolean.mk_or ctx [ e1; e2 ]

    let logand es = Z3.Boolean.mk_and ctx es

    let logor es = Z3.Boolean.mk_or ctx es

    let xor e1 e2 = Z3.Boolean.mk_xor ctx e1 e2

    let eq e1 e2 = Z3.Boolean.mk_eq ctx e1 e2

    let distinct es = Z3.Boolean.mk_distinct ctx es

    let ite cond e1 e2 = Z3.Boolean.mk_ite ctx cond e1 e2

    module Types = struct
      let int = Z3.Arithmetic.Integer.mk_sort ctx

      let real = Z3.Arithmetic.Real.mk_sort ctx

      let bool = Z3.Boolean.mk_sort ctx

      let string = Z3.Seq.mk_string_sort ctx

      let bitv n = Z3.BitVector.mk_sort ctx n

      let float eb sb = Z3.FloatingPoint.mk_sort ctx eb sb

      let ty term = Z3.Expr.get_sort term

      let to_ety sort =
        match Z3.Sort.get_sort_kind sort with
        | Z3enums.INT_SORT -> Ty.Ty_int
        | Z3enums.REAL_SORT -> Ty.Ty_real
        | Z3enums.BOOL_SORT -> Ty.Ty_bool
        | Z3enums.SEQ_SORT -> Ty.Ty_str
        | Z3enums.BV_SORT -> Ty.Ty_bitv (Z3.BitVector.get_size sort)
        | Z3enums.FLOATING_POINT_SORT ->
          let ebits = Z3.FloatingPoint.get_ebits ctx sort in
          let sbits = Z3.FloatingPoint.get_sbits ctx sort in
          Ty.Ty_fp (ebits + sbits)
        | _ -> assert false
    end

    module Interp = struct
      let to_int interp = Z.to_int @@ Z3.Arithmetic.Integer.get_big_int interp

      let to_real interp = Q.to_float @@ Z3.Arithmetic.Real.get_ratio interp

      let to_bool interp =
        match Z3.Boolean.get_bool_value interp with
        | Z3enums.L_TRUE -> true
        | Z3enums.L_FALSE -> false
        | Z3enums.L_UNDEF ->
          Fmt.failwith "Z3_mappings2: to_bool: something went terribly wrong!"

      let to_string interp = Z3.Seq.get_string ctx interp

      let to_bitv interp _n =
        assert (Z3.Expr.is_numeral interp);
        let set (s : string) (i : int) (n : char) =
          let bs = Bytes.of_string s in
          Bytes.set bs i n;
          Bytes.to_string bs
        in
        Int64.of_string (set (Z3.Expr.to_string interp) 0 '0')

      let to_float fp _eb _sb =
        assert (Z3.Expr.is_numeral fp);
        if Z3.FloatingPoint.is_numeral_nan ctx fp then Float.nan
        else if Z3.FloatingPoint.is_numeral_inf ctx fp then
          if Z3.FloatingPoint.is_numeral_negative ctx fp then Float.neg_infinity
          else Float.infinity
        else if Z3.FloatingPoint.is_numeral_zero ctx fp then
          if Z3.FloatingPoint.is_numeral_negative ctx fp then
            Float.neg Float.zero
          else Float.zero
        else
          let sort = Z3.Expr.get_sort fp in
          let ebits = Z3.FloatingPoint.get_ebits ctx sort in
          let sbits = Z3.FloatingPoint.get_sbits ctx sort in
          let _, sign = Z3.FloatingPoint.get_numeral_sign ctx fp in
          (* true => biased exponent *)
          let _, exponent =
            Z3.FloatingPoint.get_numeral_exponent_int ctx fp true
          in
          let _, significand =
            Z3.FloatingPoint.get_numeral_significand_uint ctx fp
          in
          let fp_bits =
            Int64.(
              logor
                (logor
                   (shift_left (of_int sign) (ebits + sbits - 1))
                   (shift_left exponent (sbits - 1)) )
                significand )
          in
          match ebits + sbits with
          | 32 -> Int32.float_of_bits @@ Int64.to_int32 fp_bits
          | 64 -> Int64.float_of_bits fp_bits
          | _ -> assert false
    end

    module Int = struct
      let neg e = Z3.Arithmetic.mk_unary_minus ctx e

      let to_real e = Z3.Arithmetic.Integer.mk_int2real ctx e

      let add e1 e2 = Z3.Arithmetic.mk_add ctx [ e1; e2 ]

      let sub e1 e2 = Z3.Arithmetic.mk_sub ctx [ e1; e2 ]

      let mul e1 e2 = Z3.Arithmetic.mk_mul ctx [ e1; e2 ]

      let div e1 e2 = Z3.Arithmetic.mk_div ctx e1 e2

      let rem e1 e2 = Z3.Arithmetic.Integer.mk_rem ctx e1 e2

      let pow e1 e2 = Z3.Arithmetic.mk_power ctx e1 e2

      let lt e1 e2 = Z3.Arithmetic.mk_lt ctx e1 e2

      let le e1 e2 = Z3.Arithmetic.mk_le ctx e1 e2

      let gt e1 e2 = Z3.Arithmetic.mk_gt ctx e1 e2

      let ge e1 e2 = Z3.Arithmetic.mk_ge ctx e1 e2
    end

    module Real = struct
      let neg e = Z3.Arithmetic.mk_unary_minus ctx e

      let to_int e = Z3.Arithmetic.Real.mk_real2int ctx e

      let add e1 e2 = Z3.Arithmetic.mk_add ctx [ e1; e2 ]

      let sub e1 e2 = Z3.Arithmetic.mk_sub ctx [ e1; e2 ]

      let mul e1 e2 = Z3.Arithmetic.mk_mul ctx [ e1; e2 ]

      let div e1 e2 = Z3.Arithmetic.mk_div ctx e1 e2

      let pow e1 e2 = Z3.Arithmetic.mk_power ctx e1 e2

      let lt e1 e2 = Z3.Arithmetic.mk_lt ctx e1 e2

      let le e1 e2 = Z3.Arithmetic.mk_le ctx e1 e2

      let gt e1 e2 = Z3.Arithmetic.mk_gt ctx e1 e2

      let ge e1 e2 = Z3.Arithmetic.mk_ge ctx e1 e2
    end

    module String = struct
      let v s = Z3.Seq.mk_string ctx s

      let length e = Z3.Seq.mk_seq_length ctx e

      let to_code e = Z3.Seq.mk_string_to_code ctx e

      let of_code e = Z3.Seq.mk_string_from_code ctx e

      let to_int e = Z3.Seq.mk_str_to_int ctx e

      let of_int e = Z3.Seq.mk_int_to_str ctx e

      let to_re e = Z3.Seq.mk_seq_to_re ctx e

      let in_re e1 e2 = Z3.Seq.mk_seq_in_re ctx e1 e2

      let at str ~pos = Z3.Seq.mk_seq_at ctx str pos

      let concat es = Z3.Seq.mk_seq_concat ctx es

      let is_prefix e1 ~prefix = Z3.Seq.mk_seq_prefix ctx e1 prefix

      let is_suffix e1 ~suffix = Z3.Seq.mk_seq_suffix ctx e1 suffix

      let lt a b = Z3.Seq.mk_str_lt ctx a b

      let le a b = Z3.Seq.mk_str_le ctx a b

      let contains e1 ~sub = Z3.Seq.mk_seq_contains ctx e1 sub

      let sub str ~pos ~len = Z3.Seq.mk_seq_extract ctx str pos len

      let index_of e1 ~sub ~pos = Z3.Seq.mk_seq_index ctx e1 sub pos

      let replace e1 ~pattern ~with_ =
        Z3.Seq.mk_seq_replace ctx e1 pattern with_
    end

    module Re = struct
      let star e = Z3.Seq.mk_re_star ctx e

      let plus e = Z3.Seq.mk_re_plus ctx e

      let opt e = Z3.Seq.mk_re_option ctx e

      let comp e = Z3.Seq.mk_re_complement ctx e

      let range e1 e2 = Z3.Seq.mk_re_range ctx e1 e2

      let loop e i1 i2 = Z3.Seq.mk_re_loop ctx e i1 i2

      let union es = Z3.Seq.mk_re_union ctx es

      let concat es = Z3.Seq.mk_re_concat ctx es
    end

    module Bitv = struct
      let v bv bitwidth = Z3.BitVector.mk_numeral ctx bv bitwidth

      let neg e = Z3.BitVector.mk_neg ctx e

      let lognot e = Z3.BitVector.mk_not ctx e

      let add e1 e2 = Z3.BitVector.mk_add ctx e1 e2

      let sub e1 e2 = Z3.BitVector.mk_sub ctx e1 e2

      let mul e1 e2 = Z3.BitVector.mk_mul ctx e1 e2

      let div e1 e2 = Z3.BitVector.mk_sdiv ctx e1 e2

      let div_u e1 e2 = Z3.BitVector.mk_udiv ctx e1 e2

      let logor e1 e2 = Z3.BitVector.mk_or ctx e1 e2

      let logand e1 e2 = Z3.BitVector.mk_and ctx e1 e2

      let logxor e1 e2 = Z3.BitVector.mk_xor ctx e1 e2

      let shl e1 e2 = Z3.BitVector.mk_shl ctx e1 e2

      let ashr e1 e2 = Z3.BitVector.mk_ashr ctx e1 e2

      let lshr e1 e2 = Z3.BitVector.mk_lshr ctx e1 e2

      let rem e1 e2 = Z3.BitVector.mk_srem ctx e1 e2

      let rem_u e1 e2 = Z3.BitVector.mk_urem ctx e1 e2

      let rotate_left e1 e2 = Z3.BitVector.mk_ext_rotate_left ctx e1 e2

      let rotate_right e1 e2 = Z3.BitVector.mk_ext_rotate_right ctx e1 e2

      let lt e1 e2 = Z3.BitVector.mk_slt ctx e1 e2

      let lt_u e1 e2 = Z3.BitVector.mk_ult ctx e1 e2

      let le e1 e2 = Z3.BitVector.mk_sle ctx e1 e2

      let le_u e1 e2 = Z3.BitVector.mk_ule ctx e1 e2

      let gt e1 e2 = Z3.BitVector.mk_sgt ctx e1 e2

      let gt_u e1 e2 = Z3.BitVector.mk_ugt ctx e1 e2

      let ge e1 e2 = Z3.BitVector.mk_sge ctx e1 e2

      let ge_u e1 e2 = Z3.BitVector.mk_uge ctx e1 e2

      let concat e1 e2 = Z3.BitVector.mk_concat ctx e1 e2

      let extract e ~high ~low = Z3.BitVector.mk_extract ctx high low e

      let zero_extend n e = Z3.BitVector.mk_zero_ext ctx n e

      let sign_extend n e = Z3.BitVector.mk_sign_ext ctx n e
    end

    module Float = struct
      module Rounding_mode = struct
        let rne = Z3.FloatingPoint.RoundingMode.mk_rne ctx

        let rna = Z3.FloatingPoint.RoundingMode.mk_rna ctx

        let rtp = Z3.FloatingPoint.RoundingMode.mk_rtp ctx

        let rtn = Z3.FloatingPoint.RoundingMode.mk_rtn ctx

        let rtz = Z3.FloatingPoint.RoundingMode.mk_rtz ctx
      end

      let v f eb sb = Z3.FloatingPoint.mk_numeral_f ctx f (Types.float eb sb)

      let neg e = Z3.FloatingPoint.mk_neg ctx e

      let abs e = Z3.FloatingPoint.mk_abs ctx e

      let sqrt ~rm e = Z3.FloatingPoint.mk_sqrt ctx rm e

      let is_nan e = Z3.FloatingPoint.mk_is_nan ctx e

      let round_to_integral ~rm e =
        Z3.FloatingPoint.mk_round_to_integral ctx rm e

      let add ~rm e1 e2 = Z3.FloatingPoint.mk_add ctx rm e1 e2

      let sub ~rm e1 e2 = Z3.FloatingPoint.mk_sub ctx rm e1 e2

      let mul ~rm e1 e2 = Z3.FloatingPoint.mk_mul ctx rm e1 e2

      let div ~rm e1 e2 = Z3.FloatingPoint.mk_div ctx rm e1 e2

      let min e1 e2 = Z3.FloatingPoint.mk_min ctx e1 e2

      let max e1 e2 = Z3.FloatingPoint.mk_max ctx e1 e2

      let rem e1 e2 = Z3.FloatingPoint.mk_rem ctx e1 e2

      let eq e1 e2 = Z3.FloatingPoint.mk_eq ctx e1 e2

      let lt e1 e2 = Z3.FloatingPoint.mk_lt ctx e1 e2

      let le e1 e2 = Z3.FloatingPoint.mk_leq ctx e1 e2

      let gt e1 e2 = Z3.FloatingPoint.mk_gt ctx e1 e2

      let ge e1 e2 = Z3.FloatingPoint.mk_geq ctx e1 e2

      let to_fp eb sb ~rm fp =
        Z3.FloatingPoint.mk_to_fp_float ctx rm fp (Types.float eb sb)

      let sbv_to_fp eb sb ~rm bv =
        Z3.FloatingPoint.mk_to_fp_signed ctx rm bv (Types.float eb sb)

      let ubv_to_fp eb sb ~rm bv =
        Z3.FloatingPoint.mk_to_fp_unsigned ctx rm bv (Types.float eb sb)

      let to_ubv n ~rm fp = Z3.FloatingPoint.mk_to_ubv ctx rm fp n

      let to_sbv n ~rm fp = Z3.FloatingPoint.mk_to_sbv ctx rm fp n

      let of_ieee_bv eb sb bv =
        Z3.FloatingPoint.mk_to_fp_bv ctx bv (Types.float eb sb)

      let to_ieee_bv fp = Z3.FloatingPoint.mk_to_ieee_bv ctx fp
    end

    module Func = struct
      let make name params ret = Z3.FuncDecl.mk_func_decl_s ctx name params ret

      let apply f params = Z3.FuncDecl.apply f params
    end

    module Model = struct
      let get_symbols model =
        List.map
          (fun const ->
            let x = Z3.Symbol.to_string (Z3.FuncDecl.get_name const) in
            let t = Types.to_ety (Z3.FuncDecl.get_range const) in
            Symbol.make t x )
          (Z3.Model.get_const_decls model)

      let eval ?(completion = false) model term =
        Z3.Model.eval model term completion
    end

    let pp_entry fmt (entry : Z3.Statistics.Entry.statistics_entry) =
      let key = Z3.Statistics.Entry.get_key entry in
      let value = Z3.Statistics.Entry.to_string_value entry in
      Fmt.pf fmt "(%s %s)" key value

    let pp_statistics fmt (stats : Z3.Statistics.statistics) =
      let entries = Z3.Statistics.get_entries stats in
      Fmt.list ~sep:(fun fmt () -> Fmt.pf fmt "@\n") pp_entry fmt entries

    let get_statistics (stats : Z3.Statistics.statistics) =
      let statistics = Z3.Statistics.get_entries stats in
      let add_entry map entry =
        let key = Z3.Statistics.Entry.get_key entry in
        let value =
          if Z3.Statistics.Entry.is_int entry then
            `Int (Z3.Statistics.Entry.get_int entry)
          else begin
            assert (Z3.Statistics.Entry.is_float entry);
            `Float (Z3.Statistics.Entry.get_float entry)
          end
        in
        Statistics.Map.add key value map
      in
      List.fold_left add_entry Statistics.Map.empty statistics

    let set_param (type a) (param : a Params.param) (v : a) : unit =
      match param with
      | Timeout -> Z3.Params.update_param_value ctx "timeout" (string_of_int v)
      | Model -> Z3.Params.update_param_value ctx "model" (string_of_bool v)
      | Unsat_core ->
        Z3.Params.update_param_value ctx "unsat_core" (string_of_bool v)
      | Ematching -> Z3.set_global_param "smt.ematching" (string_of_bool v)
      | Parallel -> Z3.set_global_param "parallel.enable" (string_of_bool v)
      | Num_threads ->
        Z3.set_global_param "parallel.threads.max" (string_of_int v)

    let set_params (params : Params.t) =
      List.iter (fun (Params.P (p, v)) -> set_param p v) (Params.to_list params)

    module Solver = struct
      (* TODO: parameters *)
      let make ?params ?logic () =
        Option.iter set_params params;
        let logic =
          Option.map
            (fun l -> Fmt.kstr (Z3.Symbol.mk_string ctx) "%a" Ty.pp_logic l)
            logic
        in
        Z3.Solver.mk_solver ctx logic

      let clone solver = Z3.Solver.translate solver ctx

      let push solver = Z3.Solver.push solver

      let pop solver n = Z3.Solver.pop solver n

      let reset solver = Z3.Solver.reset solver

      let add solver terms = Z3.Solver.add solver terms

      let check solver ~assumptions =
        match Z3.Solver.check solver assumptions with
        | Z3.Solver.UNKNOWN -> `Unknown
        | Z3.Solver.SATISFIABLE -> `Sat
        | Z3.Solver.UNSATISFIABLE -> `Unsat

      let model solver = Z3.Solver.get_model solver

      let add_simplifier solver =
        let simplify = Z3.Simplifier.mk_simplifier ctx "simplify" in
        let solver_eqs = Z3.Simplifier.mk_simplifier ctx "solve-eqs" in
        let then_ =
          List.map
            (Z3.Simplifier.mk_simplifier ctx)
            [ "elim-unconstrained"; "propagate-values"; "simplify" ]
        in
        Z3.Simplifier.and_then ctx simplify solver_eqs then_
        |> Z3.Solver.add_simplifier ctx solver

      let interrupt () = Z3.Tactic.interrupt ctx

      let get_statistics solver =
        get_statistics (Z3.Solver.get_statistics solver)

      let pp_statistics fmt solver =
        pp_statistics fmt @@ Z3.Solver.get_statistics solver
    end

    module Optimizer = struct
      let make () = Z3.Optimize.mk_opt ctx

      let push opt = Z3.Optimize.push opt

      let pop opt = Z3.Optimize.pop opt

      let add opt terms = Z3.Optimize.add opt terms

      let check opt =
        match Z3.Optimize.check opt with
        | Z3.Solver.UNKNOWN -> `Unknown
        | Z3.Solver.SATISFIABLE -> `Sat
        | Z3.Solver.UNSATISFIABLE -> `Unsat

      let model opt = Z3.Optimize.get_model opt

      let maximize opt term = Z3.Optimize.maximize opt term

      let minimize opt term = Z3.Optimize.minimize opt term

      let interrupt () = Z3.Tactic.interrupt ctx

      let get_statistics opt = get_statistics (Z3.Optimize.get_statistics opt)

      let pp_statistics fmt opt =
        pp_statistics fmt @@ Z3.Optimize.get_statistics opt
    end

    module Smtlib = struct
      let pp ?name ?logic ?status fmt =
        let name = Option.value name ~default:"" in
        let logic =
          Fmt.str "%a"
            (Fmt.option ~none:(fun fmt () -> Fmt.string fmt "ALL") Ty.pp_logic)
            logic
        in
        let status =
          match Option.value status ~default:`Unknown with
          | `Sat -> "sat"
          | `Unsat -> "unsat"
          | `Unknown -> "unknown"
        in
        function
        | [] -> ()
        | [ x ] ->
          Fmt.pf fmt "%s"
            (Z3.SMT.benchmark_to_smtstring ctx name logic status "" [] x)
        | hd :: tl ->
          (* Prints formulas in correct order? *)
          let tl = List.rev tl in
          Fmt.pf fmt "%s"
            (Z3.SMT.benchmark_to_smtstring ctx name logic status "" tl hd)
    end
  end

  let is_available = true

  include Make ()
end

module M' : Mappings_intf.M_with_make = M

include Mappings.Make (M)