|
|
|
|
(*
|
|
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
|
*
|
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
let%test_module _ =
|
|
|
|
|
( module struct
|
|
|
|
|
open Equality
|
|
|
|
|
|
|
|
|
|
let () = Trace.init ~margin:68 ()
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
(* let () =
|
|
|
|
|
* Trace.init ~margin:160
|
|
|
|
|
* ~config:(Result.ok_exn (Trace.parse "+Equality"))
|
|
|
|
|
* ()
|
|
|
|
|
*
|
|
|
|
|
* [@@@warning "-32"] *)
|
|
|
|
|
|
|
|
|
|
let printf pp = Format.printf "@\n%a@." pp
|
|
|
|
|
let pp = printf pp
|
|
|
|
|
let pp_classes = Format.printf "@\n@[<hv> %a@]@." pp_classes
|
|
|
|
|
let ( ! ) i = Term.integer (Z.of_int i)
|
|
|
|
|
let ( + ) = Term.add
|
|
|
|
|
let ( - ) = Term.sub
|
|
|
|
|
let ( * ) = Term.mul
|
[sledge] Simplify type conversions
Summary:
The treatment of type conversions is too complicated, non-uniform,
etc. This diff attempts to simplify things by separating integer to
integer conversions, which are interpreted, from others, which are
essentially just uninterpreted functions. Integer conversions are now
handled using two expression and term forms: Signed and
Unsigned. These each interpret their argument as either a signed or
unsigned number of a given bitwidth:
```
| Signed of {bits: int}
(** [Ap1 (Signed {bits= n}, dst, arg)] is [arg] interpreted as an
[n]-bit signed integer and injected into the [dst] type. That is,
it two's-complement--decodes the low [n] bits of the infinite
two's-complement encoding of [arg]. The injection into [dst] is a
no-op, so [dst] must be an integer type with bitwidth at least
[n]. *)
| Unsigned of {bits: int}
(** [Ap1 (Unsigned {bits= n}, dst, arg)] is [arg] interpreted as an
[n]-bit unsigned integer and injected into the [dst] type. That
is, it unsigned-binary--decodes the low [n] bits of the infinite
two's-complement encoding of [arg]. The injection into [dst] is a
no-op, so [dst] must be an integer type with bitwidth greater than
[n]. *)
| Convert of {src: Typ.t}
(** [Ap1 (Convert {src}, dst, arg)] is [arg] converted from type [src]
to type [dst], possibly with loss of information. The [src] and
[dst] types must be [Typ.convertible] and must not both be
[Integer] types. *)
```
Reviewed By: ngorogiannis
Differential Revision: D18298140
fbshipit-source-id: 690f065b4
5 years ago
|
|
|
|
let f = Term.unsigned 8
|
|
|
|
|
let g = Term.rem
|
|
|
|
|
let wrt = Var.Set.empty
|
|
|
|
|
let t_, wrt = Var.fresh "t" ~wrt
|
|
|
|
|
let u_, wrt = Var.fresh "u" ~wrt
|
|
|
|
|
let v_, wrt = Var.fresh "v" ~wrt
|
|
|
|
|
let w_, wrt = Var.fresh "w" ~wrt
|
|
|
|
|
let x_, wrt = Var.fresh "x" ~wrt
|
|
|
|
|
let y_, wrt = Var.fresh "y" ~wrt
|
|
|
|
|
let z_, wrt = Var.fresh "z" ~wrt
|
|
|
|
|
let t = Term.var t_
|
|
|
|
|
let u = Term.var u_
|
|
|
|
|
let v = Term.var v_
|
|
|
|
|
let w = Term.var w_
|
|
|
|
|
let x = Term.var x_
|
|
|
|
|
let y = Term.var y_
|
|
|
|
|
let z = Term.var z_
|
|
|
|
|
|
|
|
|
|
let of_eqs l =
|
|
|
|
|
List.fold ~init:(wrt, true_)
|
|
|
|
|
~f:(fun (us, r) (a, b) -> and_eq us a b r)
|
|
|
|
|
l
|
|
|
|
|
|> snd
|
|
|
|
|
|
|
|
|
|
let and_eq a b r = and_eq wrt a b r |> snd
|
|
|
|
|
let and_ r s = and_ wrt r s |> snd
|
|
|
|
|
let or_ r s = or_ wrt r s |> snd
|
|
|
|
|
let f1 = of_eqs [(!0, !1)]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_false f1
|
|
|
|
|
let%expect_test _ = pp f1 ; [%expect {| {sat= false; rep= []} |}]
|
|
|
|
|
let%test _ = is_false (and_eq !1 !1 f1)
|
|
|
|
|
|
|
|
|
|
let f2 = of_eqs [(x, x + !1)]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_false f2
|
|
|
|
|
let%expect_test _ = pp f2 ; [%expect {| {sat= false; rep= []} |}]
|
|
|
|
|
|
|
|
|
|
let f3 = of_eqs [(x + !0, x + !1)]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_false f3
|
|
|
|
|
let%expect_test _ = pp f3 ; [%expect {| {sat= false; rep= []} |}]
|
|
|
|
|
|
|
|
|
|
let f4 = of_eqs [(x, y); (x + !0, y + !1)]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_false f4
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp f4 ; [%expect {| {sat= false; rep= [[%y_6 ↦ %x_5]]} |}]
|
|
|
|
|
|
|
|
|
|
let t1 = of_eqs [(!1, !1)]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_true t1
|
|
|
|
|
|
|
|
|
|
let t2 = of_eqs [(x, x)]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_true t2
|
|
|
|
|
let%test _ = is_false (and_ f3 t2)
|
|
|
|
|
let%test _ = is_false (and_ t2 f3)
|
|
|
|
|
|
|
|
|
|
let r0 = true_
|
|
|
|
|
|
|
|
|
|
let%expect_test _ = pp r0 ; [%expect {| {sat= true; rep= []} |}]
|
|
|
|
|
let%expect_test _ = pp_classes r0 ; [%expect {||}]
|
|
|
|
|
let%test _ = difference r0 (f x) (f x) |> Poly.equal (Some (Z.of_int 0))
|
|
|
|
|
let%test _ = difference r0 !4 !3 |> Poly.equal (Some (Z.of_int 1))
|
|
|
|
|
|
|
|
|
|
let r1 = of_eqs [(x, y)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r1 ;
|
|
|
|
|
pp r1 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
%x_5 = %y_6
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%y_6 ↦ %x_5]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r1 x y
|
|
|
|
|
|
|
|
|
|
let r2 = of_eqs [(x, y); (f x, y); (f y, z)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r2 ;
|
|
|
|
|
pp r2 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
%x_5 = %y_6 = %z_7 = ((u8) %x_5)
|
|
|
|
|
|
|
|
|
|
{sat= true;
|
|
|
|
|
rep= [[%y_6 ↦ %x_5]; [%z_7 ↦ %x_5]; [((u8) %x_5) ↦ %x_5]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r2 x z
|
|
|
|
|
let%test _ = entails_eq (or_ r1 r2) x y
|
|
|
|
|
let%test _ = not (entails_eq (or_ r1 r2) x z)
|
|
|
|
|
let%test _ = entails_eq (or_ f1 r2) x z
|
|
|
|
|
let%test _ = entails_eq (or_ r2 f3) x z
|
|
|
|
|
let%test _ = entails_eq r2 (f y) y
|
|
|
|
|
let%test _ = entails_eq r2 (f x) (f z)
|
|
|
|
|
let%test _ = entails_eq r2 (g x y) (g z y)
|
|
|
|
|
let%test _ = difference (or_ r1 r2) x z |> Poly.equal None
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
let r = of_eqs [(w, y); (y, z)] in
|
|
|
|
|
let s = of_eqs [(x, y); (y, z)] in
|
|
|
|
|
let rs = or_ r s in
|
|
|
|
|
pp r ;
|
|
|
|
|
pp s ;
|
|
|
|
|
pp rs ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
{sat= true; rep= [[%y_6 ↦ %w_4]; [%z_7 ↦ %w_4]]}
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%y_6 ↦ %x_5]; [%z_7 ↦ %x_5]]}
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%z_7 ↦ %y_6]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ =
|
|
|
|
|
let r = of_eqs [(w, y); (y, z)] in
|
|
|
|
|
let s = of_eqs [(x, y); (y, z)] in
|
|
|
|
|
let rs = or_ r s in
|
|
|
|
|
entails_eq rs y z
|
|
|
|
|
|
|
|
|
|
let r3 = of_eqs [(g y z, w); (v, w); (g y w, t); (x, v); (x, u); (u, z)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r3 ;
|
|
|
|
|
pp r3 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
%t_1 = %u_2 = %v_3 = %w_4 = %x_5 = %z_7 = (%y_6 rem %t_1)
|
|
|
|
|
= (%y_6 rem %t_1)
|
|
|
|
|
|
|
|
|
|
{sat= true;
|
|
|
|
|
rep= [[%u_2 ↦ %t_1];
|
|
|
|
|
[%v_3 ↦ %t_1];
|
|
|
|
|
[%w_4 ↦ %t_1];
|
|
|
|
|
[%x_5 ↦ %t_1];
|
|
|
|
|
[%z_7 ↦ %t_1];
|
|
|
|
|
[(%y_6 rem %v_3) ↦ %t_1];
|
|
|
|
|
[(%y_6 rem %z_7) ↦ %t_1]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r3 t z
|
|
|
|
|
let%test _ = entails_eq r3 x z
|
|
|
|
|
let%test _ = entails_eq (and_ r2 r3) x z
|
|
|
|
|
|
|
|
|
|
let r4 = of_eqs [(w + !2, x - !3); (x - !5, y + !7); (y, z - !4)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r4 ;
|
|
|
|
|
pp r4 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
(%z_7 + -4) = %y_6 ∧ (%z_7 + 3) = %w_4 ∧ (%z_7 + 8) = %x_5
|
|
|
|
|
|
|
|
|
|
{sat= true;
|
|
|
|
|
rep= [[%w_4 ↦ (%z_7 + 3)];
|
|
|
|
|
[%x_5 ↦ (%z_7 + 8)];
|
|
|
|
|
[%y_6 ↦ (%z_7 + -4)]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r4 x (w + !5)
|
|
|
|
|
let%test _ = difference r4 x w |> Poly.equal (Some (Z.of_int 5))
|
|
|
|
|
|
|
|
|
|
let r5 = of_eqs [(x, y); (g w x, y); (g w y, f z)]
|
|
|
|
|
|
|
|
|
|
let%test _ = Var.Set.equal (fv r5) (Var.Set.of_list [w_; x_; y_; z_])
|
|
|
|
|
|
|
|
|
|
let r6 = of_eqs [(x, !1); (!1, y)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r6 ;
|
|
|
|
|
pp r6 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
1 = %x_5 = %y_6
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%x_5 ↦ 1]; [%y_6 ↦ 1]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r6 x y
|
|
|
|
|
|
|
|
|
|
let r7 = of_eqs [(v, x); (w, z); (y, z)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r7 ;
|
|
|
|
|
pp r7 ;
|
|
|
|
|
pp (and_eq x z r7) ;
|
|
|
|
|
pp_classes (and_eq x z r7) ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
%v_3 = %x_5 ∧ %w_4 = %y_6 = %z_7
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%x_5 ↦ %v_3]; [%y_6 ↦ %w_4]; [%z_7 ↦ %w_4]]}
|
|
|
|
|
|
|
|
|
|
{sat= true;
|
|
|
|
|
rep= [[%w_4 ↦ %v_3]; [%x_5 ↦ %v_3]; [%y_6 ↦ %v_3]; [%z_7 ↦ %v_3]]}
|
|
|
|
|
|
|
|
|
|
%v_3 = %w_4 = %x_5 = %y_6 = %z_7 |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
printf (List.pp " , " Term.pp) (Equality.class_of r7 t) ;
|
|
|
|
|
printf (List.pp " , " Term.pp) (Equality.class_of r7 x) ;
|
|
|
|
|
printf (List.pp " , " Term.pp) (Equality.class_of r7 z) ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
%t_1
|
|
|
|
|
|
|
|
|
|
%v_3 , %x_5
|
|
|
|
|
|
|
|
|
|
%w_4 , %z_7 , %y_6 |}]
|
|
|
|
|
|
|
|
|
|
let r7' = and_eq x z r7
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r7' ;
|
|
|
|
|
pp r7' ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
%v_3 = %w_4 = %x_5 = %y_6 = %z_7
|
|
|
|
|
|
|
|
|
|
{sat= true;
|
|
|
|
|
rep= [[%w_4 ↦ %v_3]; [%x_5 ↦ %v_3]; [%y_6 ↦ %v_3]; [%z_7 ↦ %v_3]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = normalize r7' w |> Term.equal v
|
|
|
|
|
|
|
|
|
|
let%test _ =
|
|
|
|
|
entails_eq (of_eqs [(g w x, g y z); (x, z)]) (g w x) (g w z)
|
|
|
|
|
|
|
|
|
|
let%test _ =
|
|
|
|
|
entails_eq (of_eqs [(g w x, g y w); (x, z)]) (g w x) (g w z)
|
|
|
|
|
|
|
|
|
|
let r8 = of_eqs [(x + !42, (!3 * y) + (!13 * z)); (!13 * z, x)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r8 ;
|
|
|
|
|
pp r8 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
(13 × %z_7) = %x_5 ∧ 14 = %y_6
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%x_5 ↦ (13 × %z_7)]; [%y_6 ↦ 14]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r8 y !14
|
|
|
|
|
|
|
|
|
|
let r9 = of_eqs [(x, z - !16)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r9 ;
|
|
|
|
|
pp r9 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
(%z_7 + -16) = %x_5
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%x_5 ↦ (%z_7 + -16)]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = difference r9 z (x + !8) |> Poly.equal (Some (Z.of_int 8))
|
|
|
|
|
|
|
|
|
|
let r10 = of_eqs [(!16, z - x)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp_classes r10 ;
|
|
|
|
|
pp r10 ;
|
|
|
|
|
Format.printf "@.%a@." Term.pp (z - (x + !8)) ;
|
|
|
|
|
Format.printf "@.%a@." Term.pp (normalize r10 (z - (x + !8))) ;
|
|
|
|
|
Format.printf "@.%a@." Term.pp (x + !8 - z) ;
|
|
|
|
|
Format.printf "@.%a@." Term.pp (normalize r10 (x + !8 - z)) ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
(%z_7 + -16) = %x_5
|
|
|
|
|
|
|
|
|
|
{sat= true; rep= [[%x_5 ↦ (%z_7 + -16)]]}
|
|
|
|
|
|
|
|
|
|
(-1 × %x_5 + %z_7 + -8)
|
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
|
|
|
(%x_5 + -1 × %z_7 + 8)
|
|
|
|
|
|
|
|
|
|
-8 |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = difference r10 z (x + !8) |> Poly.equal (Some (Z.of_int 8))
|
|
|
|
|
|
|
|
|
|
let%test _ =
|
|
|
|
|
difference r10 (x + !8) z |> Poly.equal (Some (Z.of_int (-8)))
|
|
|
|
|
|
|
|
|
|
let r11 = of_eqs [(!16, z - x); (x + !8 - z, z - !16 + !8 - z)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ = pp_classes r11 ; [%expect {| (%z_7 + -16) = %x_5 |}]
|
|
|
|
|
|
|
|
|
|
let r12 = of_eqs [(!16, z - x); (x + !8 - z, z + !16 + !8 - z)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ = pp_classes r12 ; [%expect {| (%z_7 + -16) = %x_5 |}]
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
let r13 = of_eqs [(Term.eq x !2, y); (Term.dq x !2, z); (y, z)]
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp r13 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
{sat= true;
|
|
|
|
|
rep= [[%z_7 ↦ %y_6]; [(%x_5 = 2) ↦ %y_6]; [(%x_5 ≠ 2) ↦ %y_6]]} |}]
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
let%test _ = not (is_false r13) (* incomplete *)
|
|
|
|
|
|
|
|
|
|
let a = Term.dq x !0
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
let r14 = of_eqs [(a, a); (x, !1)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp r14 ; [%expect {| {sat= true; rep= [[%x_5 ↦ 1]]} |}]
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r14 a Term.true_
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
let b = Term.dq y !0
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
let r14 = of_eqs [(a, b); (x, !1)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp r14 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{| {sat= true; rep= [[%x_5 ↦ 1]; [(%y_6 ≠ 0) ↦ -1]]} |}]
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r14 a Term.true_
|
|
|
|
|
let%test _ = entails_eq r14 b Term.true_
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
|
|
|
|
let b = Term.dq x !0
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
let r15 = of_eqs [(b, b); (x, !1)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp r15 ; [%expect {| {sat= true; rep= [[%x_5 ↦ 1]]} |}]
|
[sledge] Classify fully-interpreted and simplified exps differently
Summary:
For some Exp forms, Exp.solve is not complete, and this is necessary
since the result of solve is a substitution that needs to encode the
input equation as a conjunction of equations each between a variable
and an exp. This is tantamount to, stronger even than, the theory
being convex. So Exp.solve is not complete for some exps, and some of
those have constructors that perform some simplification. For example,
`(1 ≠ 0)` simplifies to `-1` (i.e. true). To enable deductions such as
`((x ≠ 0) = b) && x = 1 |- b = -1` needs the equality solver to
substitute through subexps of simplifiable exps like = and ≠, as it
does for interpreted exps like + and ×. At the same time, since
Exp.solve for non-interpreted exps cannot be complete, to enable
deductions such as `((x ≠ 0) = (y ≠ 0)) && x = 1 |- y ≠ 0` needs the
equality solver to congruence-close over subexps of simplifiable exps
such as = and ≠, as it does for uninterpreted exps.
To strengthen the equality solver in these sorts of cases, this diff
adds a new class of exps for = and ≠, and revises the equality solver
to handle them in a hybrid fashion between interpreted and
uninterpreted.
I am not currently sure whether or not this breaks the termination
proof, but I have also not managed to adapt usual divergent cases to
break this. One notable point is that simplifying = and ≠ exps always
produces genuinely simpler and smaller exps, in contrast to
e.g. polynomial simplification and gaussian elimination.
Note that the real solution to this problem is likely to be to
eliminate the i1 type in favor or a genuine boolean type, and
translate all integer operations on i1 to boolean/logical ones. Then
the disjunction implicit in e.g. equations between disequations would
appear as actual disjunction, and could be dealt with as such.
Reviewed By: jvillard
Differential Revision: D15424823
fbshipit-source-id: 67d62df1f
6 years ago
|
|
|
|
|
[sledge] Simplify type conversions
Summary:
The treatment of type conversions is too complicated, non-uniform,
etc. This diff attempts to simplify things by separating integer to
integer conversions, which are interpreted, from others, which are
essentially just uninterpreted functions. Integer conversions are now
handled using two expression and term forms: Signed and
Unsigned. These each interpret their argument as either a signed or
unsigned number of a given bitwidth:
```
| Signed of {bits: int}
(** [Ap1 (Signed {bits= n}, dst, arg)] is [arg] interpreted as an
[n]-bit signed integer and injected into the [dst] type. That is,
it two's-complement--decodes the low [n] bits of the infinite
two's-complement encoding of [arg]. The injection into [dst] is a
no-op, so [dst] must be an integer type with bitwidth at least
[n]. *)
| Unsigned of {bits: int}
(** [Ap1 (Unsigned {bits= n}, dst, arg)] is [arg] interpreted as an
[n]-bit unsigned integer and injected into the [dst] type. That
is, it unsigned-binary--decodes the low [n] bits of the infinite
two's-complement encoding of [arg]. The injection into [dst] is a
no-op, so [dst] must be an integer type with bitwidth greater than
[n]. *)
| Convert of {src: Typ.t}
(** [Ap1 (Convert {src}, dst, arg)] is [arg] converted from type [src]
to type [dst], possibly with loss of information. The [src] and
[dst] types must be [Typ.convertible] and must not both be
[Integer] types. *)
```
Reviewed By: ngorogiannis
Differential Revision: D18298140
fbshipit-source-id: 690f065b4
5 years ago
|
|
|
|
let%test _ = entails_eq r15 b (Term.signed 1 !1)
|
|
|
|
|
let%test _ = entails_eq r15 (Term.unsigned 1 b) !1
|
|
|
|
|
|
|
|
|
|
(* f(x−1)−1=x+1, f(y)+1=y−1, y+1=x ⊢ false *)
|
|
|
|
|
let r16 =
|
|
|
|
|
of_eqs [(f (x - !1) - !1, x + !1); (f y + !1, y - !1); (y + !1, x)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp r16 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
{sat= false;
|
|
|
|
|
rep= [[%x_5 ↦ (((u8) %y_6) + 3)];
|
|
|
|
|
[%y_6 ↦ (((u8) %y_6) + 2)];
|
|
|
|
|
[((u8) (%x_5 + -1)) ↦ (((u8) %y_6) + 5)];
|
|
|
|
|
[((u8) %y_6) ↦ ]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_false r16
|
|
|
|
|
|
|
|
|
|
(* f(x) = x, f(y) = y − 1, y = x ⊢ false *)
|
|
|
|
|
let r17 = of_eqs [(f x, x); (f y, y - !1); (y, x)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp r17 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
{sat= false;
|
|
|
|
|
rep= [[%x_5 ↦ (((u8) %y_6) + 1)];
|
|
|
|
|
[%y_6 ↦ (((u8) %y_6) + 1)];
|
|
|
|
|
[((u8) %x_5) ↦ (((u8) %y_6) + 1)];
|
|
|
|
|
[((u8) %y_6) ↦ ]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = is_false r17
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
let r18 = of_eqs [(f x, x); (f y, y - !1)] in
|
|
|
|
|
pp r18 ;
|
|
|
|
|
pp_classes r18 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{|
|
|
|
|
|
{sat= true;
|
|
|
|
|
rep= [[%y_6 ↦ (((u8) %y_6) + 1)];
|
|
|
|
|
[((u8) %x_5) ↦ %x_5];
|
|
|
|
|
[((u8) %y_6) ↦ ]]}
|
|
|
|
|
|
|
|
|
|
(((u8) %y_6) + 1) = %y_6
|
|
|
|
|
∧ %x_5 = ((u8) %x_5)
|
|
|
|
|
∧ ((u8) %y_6) = ((u8) (((u8) %y_6) + 1)) |}]
|
|
|
|
|
|
|
|
|
|
let r19 = of_eqs [(x, y + z); (x, !0); (y, !0)]
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
pp r19 ;
|
|
|
|
|
[%expect
|
|
|
|
|
{| {sat= true; rep= [[%x_5 ↦ 0]; [%y_6 ↦ 0]; [%z_7 ↦ 0]]} |}]
|
|
|
|
|
|
|
|
|
|
let%test _ = entails_eq r19 z !0
|
|
|
|
|
|
|
|
|
|
let%expect_test _ =
|
|
|
|
|
Equality.replay
|
|
|
|
|
{|(Solve_for_vars (() () ((Var (id 8) (name m)) (Var (id 9) (name n))))
|
|
|
|
|
((xs ()) (sat true) (rep (((Var (id 9) (name n)) (Var (id 8) (name m)))))))|} ;
|
|
|
|
|
[%expect {||}]
|
|
|
|
|
end )
|