packages feed

liquid-fixpoint-0.2.2.0: external/fixpoint/smtZ3.mem.ml

(*
 * Copyright © 2008 The Regents of the University of California. All rights reserved.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION
 * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *)

(* This file is part of the LiquidC Project *)

module H  = Hashtbl
module F  = Format
module Co = Constants
module BS = BNstats
module A  = Ast
module Sy = A.Symbol
module So = A.Sort
module SM = Sy.SMap
module P  = A.Predicate
module E  = A.Expression
module Misc = FixMisc open Misc.Ops
module SSM = Misc.StringMap
module Th = Theories

module SMTZ3 : ProverArch.SMTSOLVER = struct

let mydebug = false 

(********************************************************************************)
(************ SMT INTERFACE *****************************************************) 
(********************************************************************************)

let nb_unsat     = ref 0
let nb_pop       = ref 0
let nb_push      = ref 0

type context     = Z3.context
type symbol      = Z3.symbol
type sort        = Z3.sort
type ast         = Z3.ast
type fun_decl    = Z3.func_decl 

let var          = Z3.mk_const 
let boundVar     = Z3.mk_bound
let stringSymbol = Z3.mk_string_symbol 
let funcDecl     = Z3.mk_func_decl

let isBool c a =
  a |> Z3.get_sort c   
    |> Z3.sort_to_string c
    |> (=) "bool"

let isInt me a =
  a |> Z3.get_sort me   
    |> Z3.sort_to_string me
    |> (=) "int"

let mkAll me = Z3.mk_forall me 0 [||]

let mkRel c r a1 a2 
  = match r with
  | A.Eq 
  | A.Ueq -> Z3.mk_eq c          a1  a2  
  | A.Ne  
  | A.Une -> Z3.mk_distinct c [| a1; a2 |]
  | A.Gt  -> Z3.mk_gt c          a1  a2 
  | A.Ge  -> Z3.mk_ge c          a1  a2
  | A.Lt  -> Z3.mk_lt c          a1  a2
  | A.Le  -> Z3.mk_le c          a1  a2

let mkApp c f az  = Z3.mk_app c f (Array.of_list az)
let mkMul c a1 a2 = Z3.mk_mul c [| a1; a2|]
let mkDiv c a1 a2 = Z3.mk_div c    a1  a2
let mkAdd c a1 a2 = Z3.mk_add c [| a1; a2|]
let mkSub c a1 a2 = Z3.mk_sub c [| a1; a2|]
let mkMod = Z3.mk_mod 
let mkIte = Z3.mk_ite

let mkInt      = Z3.mk_int 
let mkReal c f = Z3.mk_numeral c (string_of_float f)
let mkTrue     = Z3.mk_true
let mkFalse    = Z3.mk_false
let mkNot      = Z3.mk_not
let mkAnd c az = Z3.mk_and c (Array.of_list az) 
let mkOr c az  = Z3.mk_or c  (Array.of_list az) 
let mkImp      = Z3.mk_implies
let mkIff      = Z3.mk_iff
let astString  = Z3.ast_to_string 
let mkIntSort  = Z3.mk_int_sort  
let mkRealSort = Z3.mk_real_sort  
let mkBoolSort = Z3.mk_bool_sort 
let mkSetSort  = Z3.mk_set_sort  
let mkEmptySet = Z3.mk_empty_set 
let mkSetAdd   = Z3.mk_set_add
let mkSetMem   = Z3.mk_set_member 
let mkSetCup   = fun me s1 s2 -> Z3.mk_set_union     me [| s1; s2 |]
let mkSetCap   = fun me s1 s2 -> Z3.mk_set_intersect me [| s1; s2 |]
let mkSetDif   = Z3.mk_set_difference
let mkSetSub   = Z3.mk_set_subset 
let mkContext  = Z3.mk_context_x 


let mkMapSort   = fun _ _ _ -> failwith "TODO: smtZ3.mem : mkMapSort"
let mkMapSelect = fun _ _ _ -> failwith "TODO: smtZ3.mem : mkMapSelect"
let mkMapStore  = fun _ _ _ _ -> failwith "TODO: smtZ3.mem : mkMapStore"


(*********************************************************)

let z3push me =
  let _ = nb_push += 1 in
  let _ = BS.time "Z3.push" Z3.push me in
  () 

let z3pop me =
  let _ = incr nb_pop in
  BS.time "Z3.pop" (Z3.pop me) 1 


(* Z3 API *)
let unsat =  
  let us_ref = ref 0 in
  fun me ->
    let _  = if mydebug then (Printf.printf "[%d] UNSAT 1 " (us_ref += 1); flush stdout) in
    let rv = (BS.time "Z3.check" Z3.check me) = Z3.L_FALSE in
    let _  = if mydebug then (Printf.printf "UNSAT 2 \n"; flush stdout) in
    let _  = if rv then ignore (nb_unsat += 1) in 
    rv

(* API *)
let assertAxiom me p =
  Co.bprintf mydebug "@[Pushing axiom %s@]@." (astString me p); 
  BS.time "Z3 assert axiom" (Z3.assert_cnstr me) p;
  asserts (not (unsat me)) "ERROR: Axiom makes background theory inconsistent!"

(* API *)
let assertDistinct me xs =
  xs |> Array.of_list |> Z3.mk_distinct me |> assertAxiom me

(* Z3 API *)
let bracket me f = Misc.bracket (fun _ -> z3push me) (fun _ -> z3pop me) f

(* Z3 API *)
let assertPreds me ps = List.iter (fun p -> BS.time "Z3.ass_cst" (Z3.assert_cnstr me) p) ps

(* Z3 API *)
let valid me p = 
  bracket me begin fun _ ->
    assertPreds me [Z3.mk_not me p];
    BS.time "unsat" unsat me 
  end

(* Z3 API *)
let contra me p = 
  bracket me begin fun _ ->
    assertPreds me [p];
    BS.time "unsat" unsat me 
  end

(* API *)
let print_stats ppf () =
  F.fprintf ppf
    "SMT stats: pushes=%d, pops=%d, unsats=%d \n" 
    !nb_push !nb_pop !nb_unsat 

end