mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-06 19:25:36 -05:00
257 lines
7.2 KiB
OCaml
257 lines
7.2 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* Cubicle *)
|
|
(* Combining model checking algorithms and SMT solvers *)
|
|
(* *)
|
|
(* Sylvain Conchon, Alain Mebsout *)
|
|
(* Mohamed Iguernelala *)
|
|
(* Universite Paris-Sud 11 *)
|
|
(* *)
|
|
(* Copyright 2011. This file is distributed under the terms of the *)
|
|
(* Apache Software License version 2.0 *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
open Format
|
|
open Num
|
|
|
|
exception Not_a_num
|
|
exception Maybe_zero
|
|
|
|
module type S = sig
|
|
type r
|
|
val compare : r -> r -> int
|
|
val term_embed : Term.t -> r
|
|
val mult : r -> r -> r
|
|
val print : Format.formatter -> r -> unit
|
|
end
|
|
|
|
module type T = sig
|
|
|
|
type r
|
|
type t
|
|
|
|
val compare : t -> t -> int
|
|
val hash : t -> int
|
|
val create : (num * r) list -> num -> Ty.t-> t
|
|
val add : t -> t -> t
|
|
val sub : t -> t -> t
|
|
val mult : t -> t -> t
|
|
val mult_const : num -> t -> t
|
|
val div : t -> t -> t * bool
|
|
val modulo : t -> t -> t
|
|
|
|
val is_empty : t -> bool
|
|
val find : r -> t -> num
|
|
val choose : t -> num * r
|
|
val subst : r -> t -> t -> t
|
|
val remove : r -> t -> t
|
|
val to_list : t -> (num * r) list * num
|
|
|
|
val print : Format.formatter -> t -> unit
|
|
val type_info : t -> Ty.t
|
|
val is_monomial : t -> (num * r * num) option
|
|
|
|
val ppmc_denominators : t -> num
|
|
val pgcd_numerators : t -> num
|
|
val normal_form : t -> t * num * num
|
|
val normal_form_pos : t -> t * num * num
|
|
end
|
|
|
|
module Make (X : S) = struct
|
|
|
|
type r = X.r
|
|
|
|
module M : Map.S with type key = r =
|
|
Map.Make(struct type t = r let compare x y = X.compare y x end)
|
|
|
|
type t = { m : num M.t; c : num; ty : Ty.t }
|
|
|
|
let compare p1 p2 =
|
|
let c = Ty.compare p1.ty p2.ty in
|
|
if c <> 0 then c
|
|
else
|
|
let c = compare_num p1.c p2.c in
|
|
if c = 0 then M.compare compare_num p1.m p2.m else c
|
|
|
|
let hash p =
|
|
abs (Hashtbl.hash p.m + 19*Hashtbl.hash p.c + 17 * Ty.hash p.ty)
|
|
|
|
let pprint fmt p =
|
|
M.iter
|
|
(fun x n ->
|
|
let s, n, op = match n with
|
|
| Int 1 -> "+", "", ""
|
|
| Int -1 -> "-", "", ""
|
|
| n ->
|
|
if n >/ Int 0 then "+", string_of_num n, "*"
|
|
else "-", string_of_num (minus_num n), "*"
|
|
in
|
|
fprintf fmt "%s%s%s%a" s n op X.print x
|
|
)p.m;
|
|
let s, n = if p.c >=/ Int 0 then "+", string_of_num p.c
|
|
else "-", string_of_num (minus_num p.c) in
|
|
fprintf fmt "%s%s" s n
|
|
|
|
|
|
let print fmt p =
|
|
M.iter
|
|
(fun t n -> fprintf fmt "%s*%a " (string_of_num n) X.print t) p.m;
|
|
fprintf fmt "%s" (string_of_num p.c);
|
|
fprintf fmt " [%a]" Ty.print p.ty
|
|
|
|
let is_num p = M.is_empty p.m
|
|
|
|
let find x m = try M.find x m with Not_found -> Int 0
|
|
|
|
let create l c ty =
|
|
let m =
|
|
List.fold_left
|
|
(fun m (n, x) ->
|
|
let n' = n +/ (find x m) in
|
|
if n' =/ (Int 0) then M.remove x m else M.add x n' m) M.empty l
|
|
in
|
|
{ m = m; c = c; ty = ty }
|
|
|
|
let add p1 p2 =
|
|
let m =
|
|
M.fold
|
|
(fun x a m ->
|
|
let a' = (find x m) +/ a in
|
|
if a' =/ (Int 0) then M.remove x m else M.add x a' m)
|
|
p2.m p1.m
|
|
in
|
|
{ m = m; c = p1.c +/ p2.c; ty = p1.ty }
|
|
|
|
let mult_const n p =
|
|
if n =/ (Int 0) then { m = M.empty; c = Int 0; ty = p.ty }
|
|
else { p with m = M.map (mult_num n) p.m; c = n */ p.c }
|
|
|
|
let mult_monome a x p =
|
|
let ax = { m = M.add x a M.empty; c = (Int 0); ty = p.ty} in
|
|
let acx = mult_const p.c ax in
|
|
let m =
|
|
M.fold
|
|
(fun xi ai m -> M.add (X.mult x xi) (a */ ai) m) p.m acx.m
|
|
in
|
|
{ acx with m = m}
|
|
|
|
let mult p1 p2 =
|
|
let p = mult_const p1.c p2 in
|
|
M.fold (fun x a p -> add (mult_monome a x p2) p) p1.m p
|
|
|
|
let sub p1 p2 =
|
|
add p1 (mult (create [] (Int (-1)) p1.ty) p2)
|
|
|
|
let div p1 p2 =
|
|
if M.is_empty p2.m then
|
|
if p2.c =/ Int 0 then raise Division_by_zero
|
|
else
|
|
let p = mult_const ((Int 1) // p2.c) p1 in
|
|
match M.is_empty p.m, p.ty with
|
|
| true, Ty.Tint -> {p with c = floor_num p.c}, false
|
|
| true, Ty.Treal -> p, false
|
|
| false, Ty.Tint -> p, true
|
|
| false, Ty.Treal -> p, false
|
|
| _ -> assert false
|
|
else raise Maybe_zero
|
|
|
|
|
|
let modulo p1 p2 =
|
|
if M.is_empty p2.m then
|
|
if p2.c =/ Int 0 then raise Division_by_zero
|
|
else
|
|
if M.is_empty p1.m then { p1 with c = mod_num p1.c p2.c }
|
|
else raise Not_a_num
|
|
else raise Maybe_zero
|
|
|
|
let find x p = M.find x p.m
|
|
|
|
let is_empty p = M.is_empty p.m
|
|
|
|
let choose p =
|
|
let tn= ref None in
|
|
(*version I : prend le premier element de la table*)
|
|
(try M.iter
|
|
(fun x a -> tn := Some (a, x); raise Exit) p.m with Exit -> ());
|
|
(*version II : prend le dernier element de la table i.e. le plus grand
|
|
M.iter (fun x a -> tn := Some (a, x)) p.m;*)
|
|
match !tn with Some p -> p | _ -> raise Not_found
|
|
|
|
let subst x p1 p2 =
|
|
try
|
|
let a = M.find x p2.m in
|
|
add (mult_const a p1) { p2 with m = M.remove x p2.m}
|
|
with Not_found -> p2
|
|
|
|
let remove x p = { p with m = M.remove x p.m }
|
|
|
|
let to_list p =
|
|
let l = M.fold (fun x a aliens -> (a, x)::aliens ) p.m [] in
|
|
List.rev l, p.c
|
|
|
|
let type_info p = p.ty
|
|
|
|
let is_monomial p =
|
|
try
|
|
M.fold
|
|
(fun x a r ->
|
|
match r with
|
|
| None -> Some (a, x, p.c)
|
|
| _ -> raise Exit)
|
|
p.m None
|
|
with Exit -> None
|
|
|
|
let denominator = function
|
|
| Num.Int _ | Num.Big_int _ -> Big_int.unit_big_int
|
|
| Num.Ratio rat -> Ratio.denominator_ratio rat
|
|
|
|
let numerator = function
|
|
| Num.Int i -> Big_int.big_int_of_int i
|
|
| Num.Big_int b -> b
|
|
| Num.Ratio rat -> Ratio.numerator_ratio rat
|
|
|
|
let pgcd_bi a b = Big_int.gcd_big_int a b
|
|
|
|
let ppmc_bi a b = Big_int.div_big_int (Big_int.mult_big_int a b) (pgcd_bi a b)
|
|
|
|
let abs_big_int_to_num b =
|
|
let b =
|
|
try Int (Big_int.int_of_big_int b)
|
|
with Failure "int_of_big_int" -> Big_int b
|
|
in
|
|
abs_num b
|
|
|
|
let ppmc_denominators {m=m} =
|
|
let res =
|
|
M.fold
|
|
(fun k c acc -> ppmc_bi (denominator c) acc)
|
|
m Big_int.unit_big_int in
|
|
abs_num (num_of_big_int res)
|
|
|
|
let pgcd_numerators {m=m} =
|
|
let res =
|
|
M.fold
|
|
(fun k c acc -> pgcd_bi (numerator c) acc)
|
|
m Big_int.zero_big_int in
|
|
abs_num (num_of_big_int res)
|
|
|
|
let normal_form ({ m = m; c = c } as p) =
|
|
if M.is_empty m then
|
|
{ p with c = Int 0 }, p.c, (Int 1)
|
|
else
|
|
let ppcm = ppmc_denominators p in
|
|
let pgcd = pgcd_numerators p in
|
|
let p = mult_const (ppcm // pgcd) p in
|
|
{ p with c = Int 0 }, p.c, (pgcd // ppcm)
|
|
|
|
let normal_form_pos p =
|
|
let p, c, d = normal_form p in
|
|
try
|
|
let a,x = choose p in
|
|
if a >/ (Int 0) then p, c, d
|
|
else mult_const (Int (-1)) p, minus_num c, minus_num d
|
|
with Not_found -> p, c, d
|
|
|
|
end
|
|
|