Skip to content

Commit 64b8ba6

Browse files
authored
fix: Make sure model generation is complete for more operators (OCamlPro#1234)
Some RIA operators are not complete even in the presence of the corresponding prelude. Add them as delayed functions to ensure we loop rather than generating an incorrect model.
1 parent c75f886 commit 64b8ba6

File tree

5 files changed

+55
-7
lines changed

5 files changed

+55
-7
lines changed

Diff for: docs/sphinx_docs/Model_generation.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,25 @@ following constructs:
4040
- Algebraic data types (including records and enumerated types in the native
4141
language)
4242

43-
- Integer and real primitives (addition, subtraction, multiplication,
44-
division, modulo, exponentiation, and comparisons), but not conversion
45-
operators between reals and integers
43+
- The following integer and real primitives: addition, subtraction,
44+
multiplication, division, modulo, comparisons, and exponentiations *with an
45+
integer exponent*
4646

4747
- Bit-vector primitives (concatenation, extraction, `bvadd`, `bvand`, `bvule`,
4848
etc.), including `bv2nat` and `int2bv`
4949

5050
Completeness for the following constructs is only guaranteed with certain
5151
command-line flags:
5252

53-
- Conversions operators between integers and reals require the
54-
`--enable-theories ria` flag
53+
- Conversions operators from integers to reals `real_of_int` and `real_is_int`
54+
require the `--enable-theories ria` flag
5555

5656
- Floating-point primitives (`ae.round`, `ae.float32` etc. in the SMT-LIB
5757
language; `float`, `float32` and `float64` in the native language) require
5858
the `--enable-theories fpa` flag
5959

60-
Model generation is known to be sometimes incomplete in the presence of arrays.
60+
Model generation is known to be sometimes incomplete in the presence of arrays,
61+
and is incomplete for the `integer_round` function.
6162

6263
## Examples
6364

Diff for: src/lib/frontend/d_cnf.ml

+5
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ type _ DStd.Builtin.t +=
164164
| Sqrt_real_excess
165165
| Ceiling_to_int of [ `Real ]
166166
| Max_real
167+
| Min_real
167168
| Max_int
168169
| Min_int
169170
| Integer_log2
@@ -360,6 +361,9 @@ let ae_fpa_builtins =
360361
(* maximum of two reals *)
361362
|> op "max_real" Max_real ([real; real] ->. real)
362363

364+
(* minimum of two reals *)
365+
|> op "min_real" Min_real ([real; real] ->. real)
366+
363367
(* maximum of two ints *)
364368
|> op "max_int" Max_int ([int; int] ->. int)
365369

@@ -1349,6 +1353,7 @@ let rec mk_expr
13491353
| B.Is_int `Real, _ -> op Real_is_int
13501354
| Ceiling_to_int `Real, _ -> op Int_ceil
13511355
| Max_real, _ -> op Max_real
1356+
| Min_real, _ -> op Min_real
13521357
| Max_int, _ -> op Max_int
13531358
| Min_int, _ -> op Min_int
13541359
| Integer_log2, _ -> op Integer_log2

Diff for: src/lib/frontend/typechecker.ml

+3
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,9 @@ module Env = struct
404404
(* maximum of two reals *)
405405
|> op "max_real" Max_real ([real; real] ->. real)
406406

407+
(* minimum of two reals *)
408+
|> op "min_real" Min_real ([real; real] ->. real)
409+
407410
(* maximum of two ints *)
408411
|> op "max_int" Max_int ([int; int] ->. int)
409412

Diff for: src/lib/reasoners/intervalCalculus.ml

+40
Original file line numberDiff line numberDiff line change
@@ -676,11 +676,51 @@ let delayed_pow uf _op = function
676676
| [ a; b ] -> calc_pow a b (E.type_info a) uf
677677
| _ -> assert false
678678

679+
let delayed_op1 ~ty fn uf _op = function
680+
| [ x ] ->
681+
let rx, exx = Uf.find uf x in
682+
Option.bind (P.is_const (poly_of rx)) @@ fun cx ->
683+
Some (alien_of (P.create [] (fn cx) ty), exx)
684+
| _ -> assert false
685+
686+
let delayed_op2 ~ty fn uf _op = function
687+
| [ x; y ] ->
688+
let rx, exx = Uf.find uf x in
689+
let ry, exy = Uf.find uf y in
690+
Option.bind (P.is_const (poly_of rx)) @@ fun cx ->
691+
Option.bind (P.is_const (poly_of ry)) @@ fun cy ->
692+
Some (alien_of (P.create [] (fn cx cy) ty), Ex.union exx exy)
693+
| _ -> assert false
694+
695+
let delayed_integer_log2 uf _op = function
696+
| [ x ] -> (
697+
let rx, exx = Uf.find uf x in
698+
let px = poly_of rx in
699+
match P.is_const px with
700+
| None -> None
701+
| Some cb ->
702+
if Q.compare cb Q.zero <= 0 then None
703+
else
704+
let res =
705+
alien_of @@
706+
P.create [] (Q.from_int (Fpa_rounding.integer_log_2 cb)) Treal
707+
in
708+
Some (res, exx)
709+
)
710+
| _ -> assert false
711+
679712
(* These are the partially interpreted functions that we know how to compute.
680713
They will be computed immediately if possible, or as soon as we learn the
681714
value of their arguments. *)
682715
let dispatch = function
683716
| Symbols.Pow -> Some delayed_pow
717+
| Symbols.Integer_log2 -> Some delayed_integer_log2
718+
| Symbols.Int_floor -> Some (delayed_op1 ~ty:Tint Numbers.Q.floor)
719+
| Symbols.Int_ceil -> Some (delayed_op1 ~ty:Tint Numbers.Q.ceiling)
720+
| Symbols.Min_int -> Some (delayed_op2 ~ty:Tint Q.min)
721+
| Symbols.Max_int -> Some (delayed_op2 ~ty:Tint Q.max)
722+
| Symbols.Min_real -> Some (delayed_op2 ~ty:Treal Q.min)
723+
| Symbols.Max_real -> Some (delayed_op2 ~ty:Treal Q.max)
684724
| _ -> None
685725

686726
let empty uf = {

Diff for: src/lib/structures/expr.ml

-1
Original file line numberDiff line numberDiff line change
@@ -2958,7 +2958,6 @@ let int_view t =
29582958
| _ ->
29592959
Fmt.failwith "The given term %a is not an integer" print t
29602960

2961-
29622961
let rounding_mode_view t =
29632962
match const_view t with
29642963
| RoundingMode m -> m

0 commit comments

Comments
 (0)