diff --git a/src_colibri2/core/colibri2_core.mli b/src_colibri2/core/colibri2_core.mli index fa2dae87b9a9ca718374c53430487c80f2175c64..fb305ef40564018b60398ac415c18c011a75c4e1 100644 --- a/src_colibri2/core/colibri2_core.mli +++ b/src_colibri2/core/colibri2_core.mli @@ -442,7 +442,11 @@ and Value : sig val of_nodevalue : Value.t -> t option + val of_value : s -> Value.t + val coerce_nodevalue : Value.t -> t + + val coerce_value : Value.t -> s end module Register (T : Colibri2_popop_lib.Popop_stdlib.NamedDatatype) : diff --git a/src_colibri2/core/structures/nodes.ml b/src_colibri2/core/structures/nodes.ml index e64e0eab1076bc98f4d92fff51e38a9c73999d66..8325f5fb1b5d56c023a1a6bf1afaeb5ffed57223 100644 --- a/src_colibri2/core/structures/nodes.ml +++ b/src_colibri2/core/structures/nodes.ml @@ -178,7 +178,11 @@ module type RegisteredValue = sig val of_nodevalue : Node.nodevalue -> t option + val of_value : s -> Node.nodevalue + val coerce_nodevalue : Node.nodevalue -> t + + val coerce_value : Node.nodevalue -> s end module ValueRegistry = ValueKind.Make_Registry (struct @@ -419,10 +423,14 @@ struct | Node.Value (_, value', _) as v when ValueKind.equal value' key -> Some v | _ -> None + let of_value v = nodevalue (index v) + let coerce_nodevalue : Value.t -> t = function | Node.Value (_, value', _) as v -> assert (ValueKind.equal value' key); v + + let coerce_value x = value (coerce_nodevalue x) end include All diff --git a/src_colibri2/core/structures/nodes.mli b/src_colibri2/core/structures/nodes.mli index 0740eff1a694076fd87a7c4f4e353f78034d57a9..1896052704f56f573edf96b602c6ea099f97da22 100644 --- a/src_colibri2/core/structures/nodes.mli +++ b/src_colibri2/core/structures/nodes.mli @@ -166,11 +166,14 @@ module type RegisteredValue = sig val value : t -> s (** Return the value from a nodevalue *) - val nodevalue : t -> Value.t + val nodevalue: t -> Value.t + val of_nodevalue: Value.t -> t option - val of_nodevalue : Value.t -> t option + val of_value: s -> Value.t val coerce_nodevalue : Value.t -> t + + val coerce_value: Value.t -> s end module RegisterValue (D : NamedDatatype) : RegisteredValue with type s = D.t @@ -187,15 +190,15 @@ module Only_for_solver : sig type sem_of_node = ThTerm : (_, 'b) ThTermKind.t * 'b -> sem_of_node val thterm : Node.t -> ThTerm.t option - (** give the sem associated with a node, make sense only for not merged + (** give the sem associated with a node, make sense only for not merged class. So only the module solver can use it *) val sem_of_node : ThTerm.t -> sem_of_node - (** give the sem associated with a node, make sense only for not merged + (** give the sem associated with a node, make sense only for not merged class. So only the module solver can use it *) val nodevalue : Node.t -> Value.t option - (** give the value associated with a node, make sense only for not merged + (** give the value associated with a node, make sense only for not merged class. So only the module solver can use it *) val node_of_thterm : ThTerm.t -> Node.t diff --git a/src_colibri2/tests/solve/smt_fp/sat/dune b/src_colibri2/tests/solve/smt_fp/sat/dune new file mode 100644 index 0000000000000000000000000000000000000000..137bdf589269179a3ae42355c4024e65ca273535 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/dune @@ -0,0 +1,13 @@ +(include dune.inc) + +(rule + (alias runtest) + (deps + (glob_files *.cnf) + (glob_files *.smt2) + (glob_files *.psmt2)) + (action + (with-stdout-to + dune.inc + (run %{exe:../../../generate_tests/generate_dune_tests.exe} . sat))) + (mode promote)) diff --git a/src_colibri2/tests/solve/smt_fp/sat/dune.inc b/src_colibri2/tests/solve/smt_fp/sat/dune.inc new file mode 100644 index 0000000000000000000000000000000000000000..449d1077432c0cafa060be3b7b7bb1d6ca12c39a --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/dune.inc @@ -0,0 +1,35 @@ +(rule (action (with-stdout-to oracle (echo "sat\n")))) +(rule (action (with-stdout-to exists_eq_not_fp_eq.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:exists_eq_not_fp_eq.smt2})))) +(rule (alias runtest) (action (diff oracle exists_eq_not_fp_eq.smt2.res))) +(rule (action (with-stdout-to inf_pos_neg_neq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:inf_pos_neg_neq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle inf_pos_neg_neq_float32.smt2.res))) +(rule (action (with-stdout-to infm_eq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:infm_eq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle infm_eq_float32.smt2.res))) +(rule (action (with-stdout-to infp_eq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:infp_eq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle infp_eq_float32.smt2.res))) +(rule (action (with-stdout-to nan_neq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:nan_neq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle nan_neq_float32.smt2.res))) +(rule (action (with-stdout-to recognize_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:recognize_float32.smt2})))) +(rule (alias runtest) (action (diff oracle recognize_float32.smt2.res))) +(rule (action (with-stdout-to recognize_float64.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:recognize_float64.smt2})))) +(rule (alias runtest) (action (diff oracle recognize_float64.smt2.res))) +(rule (action (with-stdout-to recognize_rounding_mode.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:recognize_rounding_mode.smt2})))) +(rule (alias runtest) (action (diff oracle recognize_rounding_mode.smt2.res))) +(rule (action (with-stdout-to rm_instanciation.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:rm_instanciation.smt2})))) +(rule (alias runtest) (action (diff oracle rm_instanciation.smt2.res))) +(rule (action (with-stdout-to rm_universal.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:rm_universal.smt2})))) +(rule (alias runtest) (action (diff oracle rm_universal.smt2.res))) +(rule (action (with-stdout-to simple_add_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:simple_add_float32.smt2})))) +(rule (alias runtest) (action (diff oracle simple_add_float32.smt2.res))) +(rule (action (with-stdout-to simple_eq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:simple_eq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle simple_eq_float32.smt2.res))) +(rule (action (with-stdout-to simple_mul_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:simple_mul_float32.smt2})))) +(rule (alias runtest) (action (diff oracle simple_mul_float32.smt2.res))) +(rule (action (with-stdout-to to_fp_eq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:to_fp_eq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle to_fp_eq_float32.smt2.res))) +(rule (action (with-stdout-to zero_pos_neg_neq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:zero_pos_neg_neq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle zero_pos_neg_neq_float32.smt2.res))) +(rule (action (with-stdout-to zerom_eq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:zerom_eq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle zerom_eq_float32.smt2.res))) +(rule (action (with-stdout-to zerop_eq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:zerop_eq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle zerop_eq_float32.smt2.res))) diff --git a/src_colibri2/tests/solve/smt_fp/sat/exists_eq_not_fp_eq.smt2 b/src_colibri2/tests/solve/smt_fp/sat/exists_eq_not_fp_eq.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..ab5587405feb8f2fe8a1e604ac03cd3cb53c1e6d --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/exists_eq_not_fp_eq.smt2 @@ -0,0 +1,4 @@ +(set-logic ALL) +(assert (exists ((x (_ FloatingPoint 8 24)) (y (_ FloatingPoint 8 24))) + (and (= x y) (not (fp.eq x y))))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/inf_pos_neg_neq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/inf_pos_neg_neq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..50d5f9ed42e6df44b1666710683c179c81e6ebd8 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/inf_pos_neg_neq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (not (fp.eq (_ +oo 8 24) (_ -oo 8 24)))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/infm_eq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/infm_eq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..d32861d4906d1fa6bc3d4e5070737bc0ae48cf26 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/infm_eq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq (_ -oo 8 24) (_ -oo 8 24))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/infp_eq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/infp_eq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..91101620ae68c22e4b68a4de338d6b81ba808631 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/infp_eq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq (_ +oo 8 24) (_ +oo 8 24))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/nan_neq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/nan_neq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..566d8821e60fd5b4c1d080fbcb0865a7e1ab8efd --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/nan_neq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (not (fp.eq (_ NaN 8 24) (_ NaN 8 24)))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/recognize_rounding_mode.smt2 b/src_colibri2/tests/solve/smt_fp/sat/recognize_rounding_mode.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..d2343304cbaaf0fe1bfc63eb7d2161d9b852827d --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/recognize_rounding_mode.smt2 @@ -0,0 +1,6 @@ +(set-logic ALL) +(declare-fun rm1 () RoundingMode) +(declare-fun rm2 () RoundingMode) +(assert (= rm1 rm2)) +(check-sat) + diff --git a/src_colibri2/tests/solve/smt_fp/sat/rm_instanciation.smt2 b/src_colibri2/tests/solve/smt_fp/sat/rm_instanciation.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..f881999439bff2f9f5f5ca1f62afe46b6336c187 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/rm_instanciation.smt2 @@ -0,0 +1,7 @@ +(set-logic ALL) +(declare-fun x () (_ FloatingPoint 8 24)) +(declare-fun y () (_ FloatingPoint 8 24)) +(declare-fun m () RoundingMode) +(assert (not (= RNE m))) +(assert (= (fp.add m x y) x)) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/rm_universal.smt2 b/src_colibri2/tests/solve/smt_fp/sat/rm_universal.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..78a5beceda606d4b277bf2f590023a237712ce33 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/rm_universal.smt2 @@ -0,0 +1,5 @@ +(set-logic ALL) +(declare-fun x () (_ FloatingPoint 8 24)) +(declare-fun y () (_ FloatingPoint 8 24)) +(assert (forall ((m RoundingMode)) (= (fp.add m x y) x))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/simple_add_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/simple_add_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..6f0a55c4ef55157052764d0a2b7c12ed868ede9b --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/simple_add_float32.smt2 @@ -0,0 +1,5 @@ +(set-logic ALL) +(declare-fun x () (_ FloatingPoint 8 24)) +(declare-fun y () (_ FloatingPoint 8 24)) +(assert (= (fp.add RNE x y) x)) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/simple_eq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/simple_eq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..11abb9fe5b5a84f4ad0720a9e282a4cc74c5efd7 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/simple_eq_float32.smt2 @@ -0,0 +1,5 @@ +(set-logic ALL) +(declare-fun x () (_ FloatingPoint 8 24)) +(declare-fun y () (_ FloatingPoint 8 24)) +(assert (fp.eq (fp.add RNE x y) x)) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/simple_mul_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/simple_mul_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..e0e38f6736112c5a4924579cd4cfa9b4897845de --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/simple_mul_float32.smt2 @@ -0,0 +1,5 @@ +(set-logic ALL) +(declare-fun x () (_ FloatingPoint 8 24)) +(declare-fun y () (_ FloatingPoint 8 24)) +(assert (= (fp.mul RNE x y) x)) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/to_fp_eq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/to_fp_eq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..e4402a93de6bedf59b71e5615bf66280f120d069 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/to_fp_eq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq ((_ to_fp 8 24) RNE 1.0) ((_ to_fp 8 24) RNE 1.0))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/zero_pos_neg_neq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/zero_pos_neg_neq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..510378baa30e26f198e94868794c6c43421a70aa --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/zero_pos_neg_neq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq (_ +zero 8 24) (_ -zero 8 24))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/zerom_eq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/zerom_eq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..1efb9d8cebcc7952df6fd12095e5e21c092b3cc9 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/zerom_eq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq (_ -zero 8 24) (_ -zero 8 24))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/sat/zerop_eq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/sat/zerop_eq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..b02b40f4719e076ffa01f85d2bb87e1a5e446904 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/sat/zerop_eq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq (_ +zero 8 24) (_ +zero 8 24))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/unsat/dune b/src_colibri2/tests/solve/smt_fp/unsat/dune new file mode 100644 index 0000000000000000000000000000000000000000..6d9fe5883f08bc15b92dc715d3c58c193023dbb5 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/unsat/dune @@ -0,0 +1,13 @@ +(include dune.inc) + +(rule + (alias runtest) + (deps + (glob_files *.cnf) + (glob_files *.smt2) + (glob_files *.psmt2)) + (action + (with-stdout-to + dune.inc + (run %{exe:../../../generate_tests/generate_dune_tests.exe} . unsat))) + (mode promote)) diff --git a/src_colibri2/tests/solve/smt_fp/unsat/dune.inc b/src_colibri2/tests/solve/smt_fp/unsat/dune.inc new file mode 100644 index 0000000000000000000000000000000000000000..d1c1e6097e0ef6a63763190775c76a334aa33c91 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/unsat/dune.inc @@ -0,0 +1,7 @@ +(rule (action (with-stdout-to oracle (echo "unsat\n")))) +(rule (action (with-stdout-to eq_fp_eq.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:eq_fp_eq.smt2})))) +(rule (alias runtest) (action (diff oracle eq_fp_eq.smt2.res))) +(rule (action (with-stdout-to inf_pos_neg_neq.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:inf_pos_neg_neq.smt2})))) +(rule (alias runtest) (action (diff oracle inf_pos_neg_neq.smt2.res))) +(rule (action (with-stdout-to nan_neq_float32.smt2.res (run %{bin:colibri2} --size=10M --time=30s --max-steps 3500 %{dep:nan_neq_float32.smt2})))) +(rule (alias runtest) (action (diff oracle nan_neq_float32.smt2.res))) diff --git a/src_colibri2/tests/solve/smt_fp/unsat/eq_fp_eq.smt2 b/src_colibri2/tests/solve/smt_fp/unsat/eq_fp_eq.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..92d9d453164614c9f3c1fcaab6d8e32dfa5660b7 --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/unsat/eq_fp_eq.smt2 @@ -0,0 +1,6 @@ +(set-logic ALL) +; (assert (forall ((x (_ FloatingPoint 8 24)) (y (_ FloatingPoint 8 24))) +; (=> (fp.eq x y) (= x y)))) +; should be unsat because (= NaN NaN) is true but not (fp.eq Nan NaN) +(assert (fp.eq (_ NaN 8 24) (_ NaN 8 24))) +(check-sat) diff --git a/src_colibri2/tests/solve/smt_fp/unsat/f32_f64_incompatible.smt2 b/src_colibri2/tests/solve/smt_fp/unsat/f32_f64_incompatible.smt2 deleted file mode 100644 index fdc81481ad8535a4a8787e20ec17c8619f95328a..0000000000000000000000000000000000000000 --- a/src_colibri2/tests/solve/smt_fp/unsat/f32_f64_incompatible.smt2 +++ /dev/null @@ -1,5 +0,0 @@ -(set-logic ALL) -(declare-fun x () (_ FloatingPoint 11 53)) -(declare-fun y () (_ FloatingPoint 8 24)) -(assert (= x y)) -(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/unsat/inf_pos_neg_neq.smt2 b/src_colibri2/tests/solve/smt_fp/unsat/inf_pos_neg_neq.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..3e7669912bd18cd3f61847c639ba4a4174f88c9d --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/unsat/inf_pos_neg_neq.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq (_ +oo 8 24) (_ -oo 8 24))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/solve/smt_fp/unsat/nan_neq_float32.smt2 b/src_colibri2/tests/solve/smt_fp/unsat/nan_neq_float32.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..ceca02a3db99276bf132d8860e1c39d06cf8dafe --- /dev/null +++ b/src_colibri2/tests/solve/smt_fp/unsat/nan_neq_float32.smt2 @@ -0,0 +1,3 @@ +(set-logic ALL) +(assert (fp.eq (_ NaN 8 24) (_ NaN 8 24))) +(check-sat) \ No newline at end of file diff --git a/src_colibri2/tests/tests_fp.ml b/src_colibri2/tests/tests_fp.ml index a9d8a4a57a00b8c28c056067576ffd1dbf2e0540..1c5c0a907056409c60f8e6e2aea3c4a1a747e8b3 100644 --- a/src_colibri2/tests/tests_fp.ml +++ b/src_colibri2/tests/tests_fp.ml @@ -1,3 +1,23 @@ +(*************************************************************************) +(* This file is part of Colibri2. *) +(* *) +(* Copyright (C) 2014-2021 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(*************************************************************************) + open OUnit2 open Colibri2_core open Tests_lib diff --git a/src_colibri2/theories/FP/dom_interval.ml b/src_colibri2/theories/FP/dom_interval.ml new file mode 100644 index 0000000000000000000000000000000000000000..907ed8e5150432fdbaa75281473a81a3ae4767e2 --- /dev/null +++ b/src_colibri2/theories/FP/dom_interval.ml @@ -0,0 +1,279 @@ +(*************************************************************************) +(* This file is part of Colibri2. *) +(* *) +(* Copyright (C) 2014-2021 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(*************************************************************************) + +open Colibri2_popop_lib +open Colibri2_core +open Colibri2_stdlib.Std + +let debug = Debug.register_info_flag + ~desc:"for intervals for the floating points theory" + "FP.interval" + +module D = Colibri2_theories_LRA_stages.Interval_domain + +let dom = Dom.Kind.create (module struct type t = D.t let name = "FP_ARITH" end) + +let () = Dom.register(module struct + include D + let key = dom + let merged i1 i2 = + match i1, i2 with + | None, None -> true + | Some i1, Some i2 -> D.equal i1 i2 + | _ -> false + + let merge d (i1,cl1) (i2,cl2) _ = + assert (not (Egraph.is_equal d cl1 cl2)); + match i1, cl1, i2, cl2 with + | Some i1,_, Some i2,_ -> + begin match D.inter i1 i2 with + | None -> + Debug.dprintf8 Debug.contradiction + "[FP/Dom] The intersection of %a and %a is empty when merging %a and %a" + D.pp i1 D.pp i2 + Node.pp cl1 + Node.pp cl2; + Egraph.contradiction d + | Some i -> + if not (D.equal i i1) then + Egraph.set_dom d dom cl1 i; + if not (D.equal i i2) then + Egraph.set_dom d dom cl2 i + end + | Some i1, _, _, cl2 | _, cl2, Some i1, _ -> + Egraph.set_dom d dom cl2 i1 + | None,_,None,_ -> raise Impossible + end) + +let is_zero_or_positive d n = + match Egraph.get_dom d dom n with + | None -> false + | Some p -> match D.is_comparable D.zero p with + | D.Le | D.Lt -> true + | D.Ge | D.Gt | D.Uncomparable -> false + +let is_not_zero d n = + match Egraph.get_dom d dom n with + | None -> false + | Some p -> D.absent Q.zero p + +let is_strictly_positive d n = + match Egraph.get_dom d dom n with + | None -> false + | Some p -> match D.is_comparable D.zero p with + | D.Lt -> true + | D.Le | D.Ge | D.Gt | D.Uncomparable -> false + +let is_strictly_negative d n = + match Egraph.get_dom d dom n with + | None -> false + | Some p -> match D.is_comparable D.zero p with + | D.Gt -> true + | D.Le | D.Ge | D.Lt | D.Uncomparable -> false + +let is_integer d n = + match Egraph.get_dom d dom n with + | None -> false + | Some p -> D.is_integer p + +let set_dom d node v = + match D.is_singleton v with + | Some q -> + let cst = Float32.cst' (Farith.B32.(of_q NE q)) in + Egraph.set_value d node (Float32.nodevalue cst) + | None -> + (** the pexp must be in the dom *) + Egraph.set_dom d dom node v + + +module ChoLRA = struct + let make_decision node v env = + Debug.dprintf4 Debug.decision + "[FP] decide %a on %a" D.pp v Node.pp node; + set_dom env node v + + let choose_decision node env = + let v = Opt.get_def D.reals (Egraph.get_dom env dom node) in + match D.split_heuristic v with + | Singleton _ -> Choice.DecNo + | Splitted (v1,v2) -> + DecTodo (List.map (make_decision node) (Shuffle.shufflel [v1;v2])) + | NotSplitted -> + DecTodo [make_decision node (D.singleton (D.choose v))] + + let choice n = { + Choice.prio = 1; + choice = choose_decision n; + } + +end + +let choice = ChoLRA.choice + +let upd_dom d n' v' = + match Egraph.get_dom d dom n' with + | None -> Egraph.set_dom d dom n' v' + | Some old -> + match D.inter old v' with + | None -> + Debug.dprintf6 Debug.contradiction + "[FP/Dom] The intersection of %a with %a is empty when updating %a" + D.pp old D.pp v' + Node.pp n'; + Egraph.contradiction d + | Some d' -> + if not (D.equal old d') + then Egraph.set_dom d dom n' d' + +module Monad : sig + type 'a monad = Egraph.wt -> Node.t -> 'a + val get: Node.t -> D.t option monad + val set: Node.t -> D.t option monad -> unit monad + val getb: Node.t -> bool option monad + val setb: Node.t -> bool option option monad -> unit monad + val (let+): 'b option monad -> ('b -> 'c) -> 'c option monad + val (and+): 'b option monad -> 'c option monad -> ('b * 'c) option monad + val (&&): unit monad -> unit monad -> unit monad +end = struct + type 'a monad = Egraph.wt -> Node.t -> 'a + let [@ocaml.always inline] get_dom dom n' = fun d _ -> + Egraph.get_dom d dom n' + let [@ocaml.always inline] set_dom (type b) (dom:b Dom.Kind.t) n' v' d n = + if Node.equal n n' then () else + Option.iter + (fun (v':b) -> Egraph.set_dom d dom n' v') + (v' d n) + let [@ocaml.always inline] set n' v' d n = + if Node.equal n n' then () else + Option.iter + (fun v' -> upd_dom d n' v' ) + (v' d n) + let [@ocaml.always inline] get a = get_dom dom a + let [@ocaml.always inline] get_value key n' = fun d _ -> + let open CCOpt in + let* v = Egraph.get_value d n' in + Value.value key v + let [@ocaml.always inline] set_value (type b) + (value:(module Value.S with type s = b)) + n' (v':b option option monad) : unit monad = + fun d n -> + if Node.equal n n' then () else + let module V = (val value) in + Option.iter + (Option.iter (fun v' -> Egraph.set_value d n' (V.nodevalue (V.index v')))) + (v' d n) + let getb a = get_value Boolean.dom a + let setb a = set_value (module Boolean.BoolValue) a + let [@ocaml.always inline] (let+) a (f:'b -> 'a) = fun d n -> Option.map f (a d n) + let [@ocaml.always inline] (and+) a b = fun d n -> match a d n, b d n with + | Some a, Some b -> Some (a,b) | _ -> None + let [@ocaml.always inline] (&&) a b = fun d n -> a d n; b d n + +end + +let neg_cmp = function + | `Lt -> `Ge + | `Le -> `Gt + | `Ge -> `Lt + | `Gt -> `Le + +let com_cmp = function + | `Lt -> `Gt + | `Le -> `Ge + | `Ge -> `Le + | `Gt -> `Lt + +let backward = function + | `Lt -> D.lt' + | `Gt -> D.gt' + | `Le -> D.le' + | `Ge -> D.ge' + +(** {2 Initialization} *) +let converter d (f:Ground.t) = + let r = Ground.node f in + let reg n = Egraph.register d n in + let open Monad in + let cmp test cmp a b = + reg a; reg b; + let wakeup = + setb r (let+ va = get a and+ vb = get b in + test (D.is_comparable va vb)) && + set b (let+ va = get a and+ vr = getb r in + backward (if vr then (com_cmp cmp) else (com_cmp (neg_cmp cmp))) va) && + set a (let+ vb = get b and+ vr = getb r in + backward (if vr then cmp else (neg_cmp cmp)) vb) + in + List.iter (fun n -> Daemon.attach_dom d n dom wakeup) [a;b]; + Daemon.attach_value d r Boolean.BoolValue.key (fun d n _ -> wakeup d n) + in + match Ground.sem f with + | { app = {builtin = Expr.Base; _ }; tyargs = _; args = _; ty } + when Ground.Ty.equal ty Ground.Ty.real -> + (* Egraph.register_decision d (ChoLRA.choice r) *) (* not useful for now *) + () + | { app = {builtin = Expr.Base; _ }; tyargs = _; args = _; ty } + when Ground.Ty.equal ty Ground.Ty.int -> + upd_dom d r D.integers + | { app = {builtin = Expr.Add}; tyargs = []; args; _ } -> + let (a,b) = IArray.extract2_exn args in + reg a; reg b; + let wakeup = + set r (let+ va = get a and+ vb = get b in D.add va vb) + in + List.iter (fun n -> Daemon.attach_dom d n dom wakeup) [a; b; r] + | { app = {builtin = Expr.Sub}; tyargs = []; args; _ } -> + let (a,b) = IArray.extract2_exn args in + reg a; reg b; + let wakeup = + set r (let+ va = get a and+ vb = get b in D.minus va vb) + in + List.iter (fun n -> Daemon.attach_dom d n dom wakeup) [a; b; r] + | { app = {builtin = Expr.Minus}; tyargs = []; args; _ } -> + let a = IArray.extract1_exn args in + reg a; + let wakeup = + set r (let+ va = get a in D.mult_cst Q.minus_one va) && + set a (let+ vr = get r in D.mult_cst Q.minus_one vr) + in + List.iter (fun n -> Daemon.attach_dom d n dom wakeup) [a;r] + | { app = {builtin = Expr.Lt}; tyargs = []; args; _ } -> + let a,b = IArray.extract2_exn args in + cmp (function | Uncomparable | Le -> None | Lt -> Some true | Ge | Gt -> Some false) `Lt a b + | { app = {builtin = Expr.Leq}; tyargs = []; args; _ } -> + let a,b = IArray.extract2_exn args in + cmp (function | Uncomparable | Ge -> None | Lt | Le -> Some true | Gt -> Some false) `Le a b + | { app = {builtin = Expr.Geq}; tyargs = []; args; _ } -> + let a,b = IArray.extract2_exn args in + cmp (function | Uncomparable | Le -> None | Lt -> Some false | Ge | Gt -> Some true) `Ge a b + | { app = {builtin = Expr.Gt}; tyargs = []; args; _ } -> + let a,b = IArray.extract2_exn args in + cmp (function | Uncomparable | Ge -> None | Lt | Le -> Some false | Gt -> Some true) `Gt a b + | _ -> () + +let init env = + Daemon.attach_reg_value env + Float32.key + (fun d value -> + let v = Float32.value value in + let s = D.singleton (Farith.B32.to_q v) in + Egraph.set_dom d dom (Float32.node value) s + ); + Ground.register_converter env converter diff --git a/src_colibri2/theories/FP/dune b/src_colibri2/theories/FP/dune index dc4d996e90e022c83d5f069872eaa67bf6dd1f5a..cbb3f787cb459924a1feec6571f6578d90eac56b 100644 --- a/src_colibri2/theories/FP/dune +++ b/src_colibri2/theories/FP/dune @@ -7,11 +7,19 @@ farith colibri2.stdlib colibri2.popop_lib + colibri2.theories.bool + colibri2.theories.LRA + colibri2.theories.LRA.stages + colibri2.theories.quantifiers colibri2.core) (preprocess (pps ppx_deriving.std ppx_hash)) (flags :standard + -w + +a-4-42-44-48-50-58-32-60-40-9@8 + -color + always -open Containers -open @@ -19,6 +27,10 @@ -open Std -open + Colibri2_theories_bool + -open + Colibri2_theories_quantifiers + -open Colibri2_core) (ocamlopt_flags :standard diff --git a/src_colibri2/theories/FP/float32.ml b/src_colibri2/theories/FP/float32.ml index 74b3dfd9305e32dbfe2ce73b8b6d1623d7dcd426..e4d919c80e45a1f267d9e63392cdbad7cfaaf9cf 100644 --- a/src_colibri2/theories/FP/float32.ml +++ b/src_colibri2/theories/FP/float32.ml @@ -19,29 +19,203 @@ (*************************************************************************) open Fp_value +open Colibri2_theories_LRA +open Colibri2_popop_lib + module N32 = struct let name = "Float32" end module Float32 = Value.Register(MakeFloat(Farith.B32)(N32)) include Float32 +let cst' c = index c + +let cst c = node (cst' c) + (** Initialise type interpretation TODO : fix bounds (there is a finite set of 32 bits floats) *) let init_ty d = + let specials = + let open Base.Sequence.Generator in + let (let*) = (>>=) in + run ( + let* _ = yield (Farith.B32.default_nan) in + let* _ = yield (Farith.B32.zero true) in + let* _ = yield (Farith.B32.zero false) in + let* _ = yield (Farith.B32.infm) in + yield (Farith.B32.infp)) + in + let open Base.Sequence in + let finites = posint_sequence >>| Farith.B32.of_bits in + let fp_seq = append specials finites in + let fp_values = fp_seq >>| Float32.of_value in Interp.Register.ty d (fun d ty -> match ty with | {app={builtin = Builtin.Float(8, 24);_};_} -> - let seq = - let open Interp.SeqLim in - let+ e = of_seq d posint_sequence in - (Farith.B32.of_bits e |> index |> nodevalue) - in - Some seq + let open Interp.SeqLim in + Some (of_seq d fp_values) | _ -> None) -(* TO DO : Initialise check *) -(* let init_check d = Interp.Register.check d (...) *) +let interp d n = Opt.get_exn Impossible (Egraph.get_value d n) + +let compute_ground d t = + let (!>>>) t = RealValue.coerce_value (interp d t) in + let (!>>) t = Rounding_mode.coerce_value (interp d t) in + let (!>) t = Float32.coerce_value (interp d t) in + let (!<) v = `Some (Float32.nodevalue (Float32.index v)) in + let (!<<) v = `Some (Boolean.BoolValue.nodevalue (Boolean.BoolValue.index v)) in + match Ground.sem t with + | { app = {builtin = Expr.Real_to_fp (8, 24); _}; args; _} -> + let m, r = IArray.extract2_exn args in + !< (Farith.B32.of_q !>>m !>>>r) + | { app = {builtin = Expr.Plus_infinity (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + !< (Farith.B32.infp) + | { app = {builtin = Expr.Minus_infinity (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + !< (Farith.B32.infm) + | { app = {builtin = Expr.NaN (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + !< (Farith.B32.(nan true Z.one)) + | { app = {builtin = Expr.Plus_zero (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + !< (Farith.B32.zerop) + | { app = {builtin = Expr.Minus_zero (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + !< (Farith.B32.zero true) + | { app = {builtin = Expr.Fp_add (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + !< (Farith.B32.add !>>m !>a !>b) + | { app = {builtin = Expr.Fp_sub (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + !< (Farith.B32.sub !>>m !>a !>b) + | { app = {builtin = Expr.Fp_mul (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + !< (Farith.B32.mul !>>m !>a !>b) + | { app = {builtin = Expr.Fp_abs (8, 24); _}; args; _} -> + let a = IArray.extract1_exn args in + !< (Farith.B32.abs !>a) + | { app = {builtin = Expr.Fp_div (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + if Farith.B32.(eq !>b (zero true) || eq !>b (zero false)) then `Uninterp + else !< (Farith.B32.div !>>m !>a !>b) + | { app = {builtin = Expr.Fp_eq (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + !<< (Farith.B32.eq !>a !>b) + | { app = {builtin = Expr.Fp_leq (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + !<< (Farith.B32.le !>a !>b) + | { app = {builtin = Expr.Fp_lt (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + !<< (Farith.B32.lt !>a !>b) + | { app = {builtin = Expr.Fp_geq (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + !<< (Farith.B32.ge !>a !>b) + | { app = {builtin = Expr.Fp_gt (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + !<< (Farith.B32.gt !>a !>b) + | _ -> `None + +let init_check d = Interp.Register.check d (fun d t -> + let check r = + Value.equal r (interp d (Ground.node t)) + in + match compute_ground d t with + | `None -> None + | `Some v -> Some (check v) + | `Uninterp -> + Some (Uninterp.On_uninterpreted_domain.check d t) + ) + +let attach_interp d g = + let f d g = + match compute_ground d g with + | `None -> raise Impossible + | `Some v -> Egraph.set_value d (Ground.node g) v + | `Uninterp -> Uninterp.On_uninterpreted_domain.propagate d g + in + Interp.WatchArgs.create d f g + +let converter d (f:Ground.t) = + let r = Ground.node f in + let reg n = Egraph.register d n in + let merge n = Egraph.register d n; Egraph.merge d r n in + let open Monad in + let get a = Monad.getv Float32.key a in + let getq a = Monad.getv RealValue.key a in + let set a = Monad.setv Float32.key a in + let _getb a = Monad.getv Boolean.BoolValue.key a in + let setb a = Monad.setv Boolean.BoolValue.key a in + let (!>>) t = Rounding_mode.value (Rounding_mode.coerce_nodevalue (interp d t )) in + (* let (!>>>) t = RealValue.value (RealValue.coerce_nodevalue (interp d t )) in *) + let is_zero v = Farith.B32.(eq v (zero true) || eq v (zero false)) in + let cmp cmp a b = + reg a; reg b; + attach d (setb r (let+ va = get a and+ vb = get b in cmp va vb)); + in + match Ground.sem f with + | {app={builtin=Expr.Real_to_fp (8, 24); _}; args; _} -> + let m, a = IArray.extract2_exn args in + reg m; reg a; + attach d (set r (let+ va = getq a in Farith.B32.of_q !>>m va)); + | {app={builtin=Expr.NaN (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + merge (cst (Farith.B32.nan true Z.one)) + | {app={builtin=Expr.Plus_infinity (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + merge (cst (Farith.B32.infp)) + | {app={builtin=Expr.Minus_infinity (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + merge (cst (Farith.B32.infm)) + | {app={builtin=Expr.Plus_zero (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + merge (cst (Farith.B32.zerop)) + | {app={builtin=Expr.Minus_zero (8, 24); _}; args; _} -> + assert (IArray.is_empty args); + merge (cst (Farith.B32.zero true)) + | {app={builtin=Expr.Fp_abs (8, 24); _}; args; _} -> + let a = IArray.extract1_exn args in + reg a; attach_interp d f; + attach d (set r (let+ va = get a in Farith.B32.abs va)); + | {app={builtin=Expr.Fp_add (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + reg m; reg a; reg b; attach_interp d f; + attach d (set r (let+ va = get a and+ vb = get b in Farith.B32.add !>>m va vb)); + | {app={builtin=Expr.Fp_sub (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + reg m; reg a; reg b; attach_interp d f; + attach d (set r (let+ va = get a and+ vb = get b in Farith.B32.sub !>>m va vb)); + | {app={builtin=Expr.Fp_mul (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + reg m; reg a; reg b; attach_interp d f; + attach d ( + set r (let* va = get a and+ vb = get b in + if is_zero vb then None else Some (Farith.B32.mul !>>m va vb)) + ); + | {app={builtin=Expr.Fp_div (8, 24); _}; args; _} -> + let m, a, b = IArray.extract3_exn args in + reg m; reg a; reg b; attach_interp d f; + attach d ( + set r (let* va = get a and+ vb = get b in + if is_zero vb then None else Some (Farith.B32.div !>>m va vb)) + ); + | {app={builtin=Expr.Fp_leq (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + cmp Farith.B32.le a b; attach_interp d f; + | {app={builtin=Expr.Fp_gt (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + cmp Farith.B32.gt a b; attach_interp d f; + | {app={builtin=Expr.Fp_geq (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + cmp Farith.B32.ge a b; attach_interp d f; + | {app={builtin=Expr.Fp_eq (8, 24); _}; args; _} -> + let a, b = IArray.extract2_exn args in + cmp Farith.B32.eq a b; attach_interp d f; + | _ -> () + let init env = - init_ty env + Ground.register_converter env converter; + init_ty env; + init_check env diff --git a/src_colibri2/theories/FP/float32.mli b/src_colibri2/theories/FP/float32.mli index 3d9a3ffe1e876cf88dc01c56c96d5d4df1ace0ad..9f3efaae6112d8fd67db119080a51a67bd97f858 100644 --- a/src_colibri2/theories/FP/float32.mli +++ b/src_colibri2/theories/FP/float32.mli @@ -20,4 +20,8 @@ include Value.S with type s = Farith.B32.t +val cst': Farith.B32.t -> t + +val cst: Farith.B32.t -> Node.t + val init : Egraph.wt -> unit diff --git a/src_colibri2/theories/FP/fp.ml b/src_colibri2/theories/FP/fp.ml index aa65f49318f733b293b83639f4b603ec2989d588..edd102b7cf47e01221870a9610de44a6e8a5ea3c 100644 --- a/src_colibri2/theories/FP/fp.ml +++ b/src_colibri2/theories/FP/fp.ml @@ -19,7 +19,10 @@ (*************************************************************************) let th_register env = - Float32.init env + Rounding_mode.init env; + Dom_interval.init env; + Float32.init env; + Float64.init env (* Add the theory to defaults *) let () = diff --git a/src_colibri2/theories/FP/fp_value.mli b/src_colibri2/theories/FP/fp_value.mli index 876601c9fb35d08360686845036b3e8a9ae4ef69..6c759aa446a375910404bdaba4f48383a5ed0b12 100644 --- a/src_colibri2/theories/FP/fp_value.mli +++ b/src_colibri2/theories/FP/fp_value.mli @@ -30,4 +30,4 @@ module type FloatName = sig val name : string end Helper to extend a module of type [Farith.S] into a module of type [Value.Kind.Value] *) -module MakeFloat (F : Farith.S) (N : FloatName) : Colibri2_popop_lib.Popop_stdlib.NamedDatatype with type t = F.t +module MakeFloat (F : Farith.S) (_ : FloatName) : Colibri2_popop_lib.Popop_stdlib.NamedDatatype with type t = F.t diff --git a/src_colibri2/theories/FP/rounding_mode.ml b/src_colibri2/theories/FP/rounding_mode.ml new file mode 100644 index 0000000000000000000000000000000000000000..1d896b9f41d2afa67f10c01b8e08850f4db3ccdf --- /dev/null +++ b/src_colibri2/theories/FP/rounding_mode.ml @@ -0,0 +1,126 @@ +(*************************************************************************) +(* This file is part of Colibri2. *) +(* *) +(* Copyright (C) 2014-2021 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(*************************************************************************) + +open Colibri2_popop_lib +open Popop_stdlib + +module FarithModes = struct + let string_of_mode = function + | Farith.NE -> "RoundNearestTiesToEven" + | Farith.NA -> "RoundNearestTiesToAway" + | Farith.UP -> "RoundTowardPositive" + | Farith.DN -> "RoundTowardNegative" + | Farith.ZR -> "RoundTowardZero" + + type t = Farith.mode + + let hash = Hashtbl.hash + + let compare = Stdlib.compare + + let equal = Stdlib.(=) + + let hash_fold_t s t = Base.Hash.fold_int s (hash t) + + let sexp_of_t t = Base.Sexp.Atom (string_of_mode t) + + let pp fmt t = Format.pp_print_string fmt (string_of_mode t) +end + +module Modes = Value.Register(struct + include FarithModes + module M = Map.Make(FarithModes) + module S = Extset.MakeOfMap(M) + module H = XHashtbl.Make(FarithModes) + let name = "RoundingMode" + end) + +include Modes + +let rounding_mode_sequence = + let open Base.Sequence.Generator in + ( + yield Farith.NE >>= fun () -> + yield Farith.NA >>= fun () -> + yield Farith.UP >>= fun () -> + yield Farith.DN >>= fun () -> + yield Farith.ZR + ) |> run + +let init_ty d = + Interp.Register.ty d (fun d ty -> + match ty with + | {app={builtin = Expr.RoundingMode;_};_} -> + let seq = + let open Interp.SeqLim in + let+ e = of_seq d rounding_mode_sequence in + (e |> index |> nodevalue) + in + Some seq + | _ -> None + ) + +let interp d n = Opt.get_exn Impossible (Egraph.get_value d n) + +let compute_cst t = + let (!<) v = `Some (Modes.nodevalue (Modes.index v)) in + match Ground.sem t with + | { app = {builtin = Expr.RoundNearestTiesToEven; _}; _} -> + !< Farith.NE + | { app = {builtin = Expr.RoundNearestTiesToAway; _}; _} -> + !< Farith.NA + | { app = {builtin = Expr.RoundTowardNegative; _}; _} -> + !< Farith.DN + | { app = {builtin = Expr.RoundTowardPositive; _}; _} -> + !< Farith.UP + | { app = {builtin = Expr.RoundTowardZero; _}; _} -> + !< Farith.ZR + | _ -> `None + +let converter d f = + let r = Ground.node f in + let cst c = node (index c) in + let merge n = Egraph.register d n; Egraph.merge d r n in + match Ground.sem f with + | { app = {builtin = Expr.RoundNearestTiesToEven; _}; _} -> + merge (cst Farith.NE) + | { app = {builtin = Expr.RoundNearestTiesToAway; _}; _} -> + merge (cst Farith.NA) + | { app = {builtin = Expr.RoundTowardNegative; _}; _} -> + merge (cst Farith.DN) + | { app = {builtin = Expr.RoundTowardPositive; _}; _} -> + merge (cst Farith.UP) + | { app = {builtin = Expr.RoundTowardZero; _}; _} -> + merge (cst Farith.ZR) + | _ -> () + +let init_check d = Interp.Register.check d (fun d t -> + let check r = + Value.equal r (interp d (Ground.node t)) + in + match compute_cst t with + | `None -> None + | `Some v -> Some (check v) + ) + +let init env = + Ground.register_converter env converter; + init_ty env; + init_check env diff --git a/src_colibri2/theories/FP/rounding_mode.mli b/src_colibri2/theories/FP/rounding_mode.mli new file mode 100644 index 0000000000000000000000000000000000000000..07d44840f8cd6f6e13c76968fe8c592c546f77e1 --- /dev/null +++ b/src_colibri2/theories/FP/rounding_mode.mli @@ -0,0 +1,23 @@ +(*************************************************************************) +(* This file is part of Colibri2. *) +(* *) +(* Copyright (C) 2014-2021 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(*************************************************************************) + +include Value.S with type s = Farith.mode + +val init : Egraph.wt -> unit