src/HOL/Tools/Presburger/presburger.ML
changeset 14758 af3b71a46a1c
parent 14353 79f9fbef9106
child 14801 2d27b5ebc447
equal deleted inserted replaced
14757:556ce89b7d41 14758:af3b71a46a1c
     4     License:    GPL (GNU GENERAL PUBLIC LICENSE)
     4     License:    GPL (GNU GENERAL PUBLIC LICENSE)
     5 
     5 
     6 Tactic for solving arithmetical Goals in Presburger Arithmetic
     6 Tactic for solving arithmetical Goals in Presburger Arithmetic
     7 *)
     7 *)
     8 
     8 
       
     9 (* This version of presburger deals with occurences of functional symbols in the subgoal and abstract over them to try to prove the more general formula. It then resolves with the subgoal. To disable this feature call the procedure with the parameter no_abs
       
    10 *)
       
    11 
     9 signature PRESBURGER = 
    12 signature PRESBURGER = 
    10 sig
    13 sig
    11  val presburger_tac : bool -> int -> tactic
    14  val presburger_tac : bool -> bool -> int -> tactic
    12  val presburger_method : bool -> int -> Proof.method
    15  val presburger_method : bool -> bool -> int -> Proof.method
    13  val setup : (theory -> theory) list
    16  val setup : (theory -> theory) list
    14  val trace : bool ref
    17  val trace : bool ref
    15 end;
    18 end;
    16 
    19 
    17 structure Presburger: PRESBURGER =
    20 structure Presburger: PRESBURGER =
    23 (*-----------------------------------------------------------------*)
    26 (*-----------------------------------------------------------------*)
    24 (*cooper_pp: provefunction for the one-exstance quantifier elimination*)
    27 (*cooper_pp: provefunction for the one-exstance quantifier elimination*)
    25 (* Here still only one problem : The proof for the arithmetical transformations done on the dvd atomic formulae*)
    28 (* Here still only one problem : The proof for the arithmetical transformations done on the dvd atomic formulae*)
    26 (*-----------------------------------------------------------------*)
    29 (*-----------------------------------------------------------------*)
    27 
    30 
    28 val presburger_ss = simpset_of (theory "Presburger");
    31 fun cooper_pp sg (fm as e$Abs(xn,xT,p)) = 
    29 
       
    30 fun cooper_pp sg vrl (fm as e$Abs(xn,xT,p)) = 
       
    31   let val (xn1,p1) = variant_abs (xn,xT,p)
    32   let val (xn1,p1) = variant_abs (xn,xT,p)
    32   in (CooperProof.cooper_prv sg (Free (xn1, xT)) p1 vrl) end;
    33   in (CooperProof.cooper_prv sg (Free (xn1, xT)) p1) end;
    33 
    34 
    34 fun mnnf_pp sg fm = CooperProof.proof_of_cnnf sg fm
    35 fun mnnf_pp sg fm = CooperProof.proof_of_cnnf sg fm
    35   (CooperProof.proof_of_evalc sg);
    36   (CooperProof.proof_of_evalc sg);
    36 
    37 
    37 fun mproof_of_int_qelim sg fm =
    38 fun tmproof_of_int_qelim sg fm =
    38   Qelim.proof_of_mlift_qelim sg CooperDec.is_arith_rel
    39   Qelim.tproof_of_mlift_qelim sg CooperDec.is_arith_rel
    39     (CooperProof.proof_of_linform sg) (mnnf_pp sg) (cooper_pp sg) fm;
    40     (CooperProof.proof_of_linform sg) (mnnf_pp sg) (cooper_pp sg) fm;
       
    41 
    40 
    42 
    41 (* Theorems to be used in this tactic*)
    43 (* Theorems to be used in this tactic*)
    42 
    44 
    43 val zdvd_int = thm "zdvd_int";
    45 val zdvd_int = thm "zdvd_int";
    44 val zdiff_int_split = thm "zdiff_int_split";
    46 val zdiff_int_split = thm "zdiff_int_split";
    61   | add_term_typed_consts (Abs (_, _, t), cs) = add_term_typed_consts (t, cs)
    63   | add_term_typed_consts (Abs (_, _, t), cs) = add_term_typed_consts (t, cs)
    62   | add_term_typed_consts (_, cs) = cs;
    64   | add_term_typed_consts (_, cs) = cs;
    63 
    65 
    64 fun term_typed_consts t = add_term_typed_consts(t,[]);
    66 fun term_typed_consts t = add_term_typed_consts(t,[]);
    65 
    67 
       
    68 (* put a term into eta long beta normal form *)
       
    69 fun eta_long Ts (Abs (s, T, t)) = Abs (s, T, eta_long (T :: Ts) t)
       
    70   | eta_long Ts t = (case strip_comb t of
       
    71       (Abs _, _) => eta_long Ts (Envir.beta_norm t)
       
    72     | (u, ts) => 
       
    73       let
       
    74         val Us = binder_types (fastype_of1 (Ts, t));
       
    75         val i = length Us
       
    76       in list_abs (map (pair "x") Us,
       
    77         list_comb (incr_boundvars i u, map (eta_long (rev Us @ Ts))
       
    78           (map (incr_boundvars i) ts @ map Bound (i - 1 downto 0))))
       
    79       end);
       
    80 
    66 (* Some Types*)
    81 (* Some Types*)
    67 val bT = HOLogic.boolT;
    82 val bT = HOLogic.boolT;
    68 val iT = HOLogic.intT;
    83 val iT = HOLogic.intT;
    69 val binT = HOLogic.binT;
    84 val binT = HOLogic.binT;
    70 val nT = HOLogic.natT;
    85 val nT = HOLogic.natT;
    92    ("op +", iT --> iT --> iT),
   107    ("op +", iT --> iT --> iT),
    93    ("op -", iT --> iT --> iT),
   108    ("op -", iT --> iT --> iT),
    94    ("op *", iT --> iT --> iT), 
   109    ("op *", iT --> iT --> iT), 
    95    ("HOL.abs", iT --> iT),
   110    ("HOL.abs", iT --> iT),
    96    ("uminus", iT --> iT),
   111    ("uminus", iT --> iT),
    97    ("HOL.max", iT --> iT --> iT),
       
    98    ("HOL.min", iT --> iT --> iT),
       
    99 
   112 
   100    ("op <=", nT --> nT --> bT),
   113    ("op <=", nT --> nT --> bT),
   101    ("op =", nT --> nT --> bT),
   114    ("op =", nT --> nT --> bT),
   102    ("op <", nT --> nT --> bT),
   115    ("op <", nT --> nT --> bT),
   103    ("Divides.op dvd", nT --> nT --> bT),
   116    ("Divides.op dvd", nT --> nT --> bT),
   105    ("Divides.op mod", nT --> nT --> nT),
   118    ("Divides.op mod", nT --> nT --> nT),
   106    ("op +", nT --> nT --> nT),
   119    ("op +", nT --> nT --> nT),
   107    ("op -", nT --> nT --> nT),
   120    ("op -", nT --> nT --> nT),
   108    ("op *", nT --> nT --> nT), 
   121    ("op *", nT --> nT --> nT), 
   109    ("Suc", nT --> nT),
   122    ("Suc", nT --> nT),
   110    ("HOL.max", nT --> nT --> nT),
       
   111    ("HOL.min", nT --> nT --> nT),
       
   112 
   123 
   113    ("Numeral.bin.Bit", binT --> bT --> binT),
   124    ("Numeral.bin.Bit", binT --> bT --> binT),
   114    ("Numeral.bin.Pls", binT),
   125    ("Numeral.bin.Pls", binT),
   115    ("Numeral.bin.Min", binT),
   126    ("Numeral.bin.Min", binT),
   116    ("Numeral.number_of", binT --> iT),
   127    ("Numeral.number_of", binT --> iT),
   117    ("Numeral.number_of", binT --> nT),
   128    ("Numeral.number_of", binT --> nT),
   118    ("0", nT),
   129    ("0", nT),
   119    ("0", iT),
   130    ("0", iT),
   120    ("1", nT),
   131    ("1", nT),
   121    ("1", iT),
   132    ("1", iT),
   122 
       
   123    ("False", bT),
   133    ("False", bT),
   124    ("True", bT)];
   134    ("True", bT)];
   125 
       
   126 (*returns true if the formula is relevant for presburger arithmetic tactic*)
       
   127 fun relevant ps t = (term_typed_consts t) subset allowed_consts andalso
       
   128   map (fn i => snd (nth_elem (i, ps))) (loose_bnos t) @
       
   129   map (snd o dest_Free) (term_frees t) @ map (snd o dest_Var) (term_vars t)
       
   130   subset [iT, nT];
       
   131 
   135 
   132 (* Preparation of the formula to be sent to the Integer quantifier *)
   136 (* Preparation of the formula to be sent to the Integer quantifier *)
   133 (* elimination procedure                                           *)
   137 (* elimination procedure                                           *)
   134 (* Transforms meta implications and meta quantifiers to object     *)
   138 (* Transforms meta implications and meta quantifiers to object     *)
   135 (* implications and object quantifiers                             *)
   139 (* implications and object quantifiers                             *)
   136 
   140 
   137 fun prepare_for_presburger q fm = 
   141 
       
   142 (*==================================*)
       
   143 (* Abstracting on subterms  ========*)
       
   144 (*==================================*)
       
   145 (* Returns occurences of terms that are function application of type int or nat*)
       
   146 
       
   147 fun getfuncs fm = case strip_comb fm of
       
   148     (Free (_, T), ts as _ :: _) =>
       
   149       if body_type T mem [iT, nT] 
       
   150          andalso not (ts = []) andalso forall (null o loose_bnos) ts 
       
   151       then [fm]
       
   152       else foldl op union ([], map getfuncs ts)
       
   153   | (Var (_, T), ts as _ :: _) =>
       
   154       if body_type T mem [iT, nT] 
       
   155          andalso not (ts = []) andalso forall (null o loose_bnos) ts then [fm]
       
   156       else foldl op union ([], map getfuncs ts)
       
   157   | (Const (s, T), ts) =>
       
   158       if (s, T) mem allowed_consts orelse not (body_type T mem [iT, nT])
       
   159       then foldl op union ([], map getfuncs ts)
       
   160       else [fm]
       
   161   | (Abs (s, T, t), _) => getfuncs t
       
   162   | _ => [];
       
   163 
       
   164 
       
   165 fun abstract_pres sg fm = 
       
   166   foldr (fn (t, u) =>
       
   167       let val T = fastype_of t
       
   168       in all T $ Abs ("x", T, abstract_over (t, u)) end)
       
   169          (getfuncs fm, fm);
       
   170 
       
   171 
       
   172 
       
   173 (* hasfuncs_on_bounds dont care of the type of the functions applied!
       
   174  It returns true if there is a subterm coresponding to the application of
       
   175  a function on a bounded variable.
       
   176 
       
   177  Function applications are allowed only for well predefined functions a 
       
   178  consts*)
       
   179 
       
   180 fun has_free_funcs fm  = case strip_comb fm of
       
   181     (Free (_, T), ts as _ :: _) => 
       
   182       if (body_type T mem [iT,nT]) andalso (not (T mem [iT,nT]))
       
   183       then true
       
   184       else exists (fn x => x) (map has_free_funcs ts)
       
   185   | (Var (_, T), ts as _ :: _) =>
       
   186       if (body_type T mem [iT,nT]) andalso not (T mem [iT,nT])
       
   187       then true
       
   188       else exists (fn x => x) (map has_free_funcs ts)
       
   189   | (Const (s, T), ts) =>  exists (fn x => x) (map has_free_funcs ts)
       
   190   | (Abs (s, T, t), _) => has_free_funcs t
       
   191   |_ => false;
       
   192 
       
   193 
       
   194 (*returns true if the formula is relevant for presburger arithmetic tactic
       
   195 The constants occuring in term t should be a subset of the allowed_consts
       
   196  There also should be no occurences of application of functions on bounded 
       
   197  variables. Whenever this function will be used, it will be ensured that t 
       
   198  will not contain subterms with function symbols that could have been 
       
   199  abstracted over.*)
       
   200  
       
   201 fun relevant ps t = (term_typed_consts t) subset allowed_consts andalso 
       
   202   map (fn i => snd (nth_elem (i, ps))) (loose_bnos t) @
       
   203   map (snd o dest_Free) (term_frees t) @ map (snd o dest_Var) (term_vars t)
       
   204   subset [iT, nT]
       
   205   andalso not (has_free_funcs t);
       
   206 
       
   207 
       
   208 fun prepare_for_presburger sg q fm = 
   138   let
   209   let
   139     val ps = Logic.strip_params fm
   210     val ps = Logic.strip_params fm
   140     val hs = map HOLogic.dest_Trueprop (Logic.strip_assums_hyp fm)
   211     val hs = map HOLogic.dest_Trueprop (Logic.strip_assums_hyp fm)
   141     val c = HOLogic.dest_Trueprop (Logic.strip_assums_concl fm)
   212     val c = HOLogic.dest_Trueprop (Logic.strip_assums_concl fm)
   142     val _ = if relevant (rev ps) c then () else raise CooperDec.COOPER
   213     val _ = if relevant (rev ps) c then () 
       
   214                else  (trace_msg ("Conclusion is not a presburger term:\n" ^
       
   215              Sign.string_of_term sg c); raise CooperDec.COOPER)
   143     fun mk_all ((s, T), (P,n)) =
   216     fun mk_all ((s, T), (P,n)) =
   144       if 0 mem loose_bnos P then
   217       if 0 mem loose_bnos P then
   145         (HOLogic.all_const T $ Abs (s, T, P), n)
   218         (HOLogic.all_const T $ Abs (s, T, P), n)
   146       else (incr_boundvars ~1 P, n-1)
   219       else (incr_boundvars ~1 P, n-1)
   147     fun mk_all2 (v, t) = HOLogic.all_const (fastype_of v) $ lambda v t;
   220     fun mk_all2 (v, t) = HOLogic.all_const (fastype_of v) $ lambda v t;
   159 
   232 
   160 (* object implication to meta---*)
   233 (* object implication to meta---*)
   161 fun mp_step n th = if (n=0) then th else (mp_step (n-1) th) RS mp;
   234 fun mp_step n th = if (n=0) then th else (mp_step (n-1) th) RS mp;
   162 
   235 
   163 (* the presburger tactic*)
   236 (* the presburger tactic*)
   164 fun presburger_tac q i = ObjectLogic.atomize_tac i THEN (fn st =>
   237 
       
   238 (* Parameters : q = flag for quantify ofer free variables ; 
       
   239                 a = flag for abstracting over function occurences
       
   240                 i = subgoal  *)
       
   241 
       
   242 fun presburger_tac q a i = ObjectLogic.atomize_tac i THEN (fn st =>
   165   let
   243   let
   166     val g = BasisLibrary.List.nth (prems_of st, i - 1);
   244     val g = BasisLibrary.List.nth (prems_of st, i - 1)
   167     val sg = sign_of_thm st;
   245     val sg = sign_of_thm st
       
   246     (* The Abstraction step *)
       
   247     val g' = if a then abstract_pres sg g else g
   168     (* Transform the term*)
   248     (* Transform the term*)
   169     val (t,np,nh) = prepare_for_presburger q g
   249     val (t,np,nh) = prepare_for_presburger sg q g'
   170     (* Some simpsets for dealing with mod div abs and nat*)
   250     (* Some simpsets for dealing with mod div abs and nat*)
   171 
       
   172     val simpset0 = HOL_basic_ss
   251     val simpset0 = HOL_basic_ss
   173       addsimps [mod_div_equality', Suc_plus1]
   252       addsimps [mod_div_equality', Suc_plus1]
   174       addsplits [split_zdiv, split_zmod, split_div', split_min, split_max]
   253       addsplits [split_zdiv, split_zmod, split_div', split_min, split_max]
   175     (* Simp rules for changing (n::int) to int n *)
   254     (* Simp rules for changing (n::int) to int n *)
   176     val simpset1 = HOL_basic_ss
   255     val simpset1 = HOL_basic_ss
   181 
   260 
   182     val simpset2 = HOL_basic_ss
   261     val simpset2 = HOL_basic_ss
   183       addsimps [nat_0_le, all_nat, ex_nat, number_of1, number_of2, int_0, int_1]
   262       addsimps [nat_0_le, all_nat, ex_nat, number_of1, number_of2, int_0, int_1]
   184       addcongs [conj_le_cong, imp_le_cong]
   263       addcongs [conj_le_cong, imp_le_cong]
   185     (* simp rules for elimination of abs *)
   264     (* simp rules for elimination of abs *)
   186 
       
   187     val simpset3 = HOL_basic_ss addsplits [abs_split]
   265     val simpset3 = HOL_basic_ss addsplits [abs_split]
   188 	      
       
   189     val ct = cterm_of sg (HOLogic.mk_Trueprop t)
   266     val ct = cterm_of sg (HOLogic.mk_Trueprop t)
   190 
       
   191     (* Theorem for the nat --> int transformation *)
   267     (* Theorem for the nat --> int transformation *)
   192     val pre_thm = Seq.hd (EVERY
   268     val pre_thm = Seq.hd (EVERY
   193       [simp_tac simpset0 i,
   269       [simp_tac simpset0 1,
   194        TRY (simp_tac simpset1 i), TRY (simp_tac simpset2 i),
   270        TRY (simp_tac simpset1 1), TRY (simp_tac simpset2 1),
   195        TRY (simp_tac simpset3 i), TRY (simp_tac presburger_ss i)]
   271        TRY (simp_tac simpset3 1)]
   196       (trivial ct))
   272       (trivial ct))
   197 
   273     fun assm_tac i = REPEAT_DETERM_N nh (assume_tac i)
   198     fun assm_tac i = REPEAT_DETERM_N nh (assume_tac i);
       
   199 
       
   200     (* The result of the quantifier elimination *)
   274     (* The result of the quantifier elimination *)
   201     val (th, tac) = case (prop_of pre_thm) of
   275     val (th, tac) = case (prop_of pre_thm) of
   202         Const ("==>", _) $ (Const ("Trueprop", _) $ t1) $ _ =>
   276         Const ("==>", _) $ (Const ("Trueprop", _) $ t1) $ _ =>
   203           (trace_msg ("calling procedure with term:\n" ^
   277           (trace_msg ("calling procedure with term:\n" ^
   204              Sign.string_of_term sg t1);
   278              Sign.string_of_term sg t1);
   205            ((mproof_of_int_qelim sg (Pattern.eta_long [] t1) RS iffD2) RS pre_thm,
   279            ((tmproof_of_int_qelim sg (Pattern.eta_long [] t1) RS iffD2) RS pre_thm,
   206             assm_tac (i + 1) THEN (if q then I else TRY) (rtac TrueI i)))
   280             assm_tac (i + 1) THEN (if q then I else TRY) (rtac TrueI i)))
   207       | _ => (pre_thm, assm_tac i)
   281       | _ => (pre_thm, assm_tac i)
   208   in (rtac (((mp_step nh) o (spec_step np)) th) i THEN tac) st
   282   in (rtac (((mp_step nh) o (spec_step np)) th) i 
       
   283       THEN tac) st
   209   end handle Subscript => no_tac st | CooperDec.COOPER => no_tac st);
   284   end handle Subscript => no_tac st | CooperDec.COOPER => no_tac st);
   210 
   285 
   211 fun presburger_args meth =
   286 fun presburger_args meth =
   212   Method.simple_args (Scan.optional (Args.$$$ "no_quantify" >> K false) true)
   287  let val parse_flag = 
   213     (fn q => fn _ => meth q 1);
   288          Args.$$$ "no_quantify" >> K (apfst (K false))
   214 
   289       || Args.$$$ "no_abs" >> K (apsnd (K false));
   215 fun presburger_method q i = Method.METHOD (fn facts =>
   290  in
   216   Method.insert_tac facts 1 THEN presburger_tac q i)
   291    Method.simple_args 
       
   292   (Scan.optional (Args.$$$ "(" |-- Args.list1 parse_flag --| Args.$$$ ")") [] >>
       
   293     curry (foldl op |>) (true, true))
       
   294     (fn (q,a) => fn _ => meth q a 1)
       
   295   end;
       
   296 
       
   297 fun presburger_method q a i = Method.METHOD (fn facts =>
       
   298   Method.insert_tac facts 1 THEN presburger_tac q a i)
   217 
   299 
   218 val setup =
   300 val setup =
   219   [Method.add_method ("presburger",
   301   [Method.add_method ("presburger",
   220      presburger_args presburger_method,
   302      presburger_args presburger_method,
   221      "decision procedure for Presburger arithmetic"),
   303      "decision procedure for Presburger arithmetic"),
   222    ArithTheoryData.map (fn {splits, inj_consts, discrete, presburger} =>
   304    ArithTheoryData.map (fn {splits, inj_consts, discrete, presburger} =>
   223      {splits = splits, inj_consts = inj_consts, discrete = discrete,
   305      {splits = splits, inj_consts = inj_consts, discrete = discrete,
   224       presburger = Some (presburger_tac true)})];
   306       presburger = Some (presburger_tac true true)})];
   225 
   307 
   226 end;
   308 end;
   227 
   309 
   228 val presburger_tac = Presburger.presburger_tac true;
   310 val presburger_tac = Presburger.presburger_tac true true;