src/Provers/Arith/cancel_div_mod.ML
author wenzelm
Wed, 12 Jul 2006 21:19:17 +0200
changeset 20114 a1bb4bc68ff3
parent 20044 92cc2f4c7335
child 22997 d4f3b015b50b
permissions -rw-r--r--
prove_conv: Variable.import_terms instead of Term.addhoc_freeze_vars; tuned;

(*  Title:      Provers/Arith/cancel_div_mod.ML
    ID:         $Id$
    Author:     Tobias Nipkow, TU Muenchen

Cancel div and mod terms:

  A + n*(m div n) + B + (m mod n) + C  ==  A + B + C + m

FIXME: Is parameterized but assumes for simplicity that + and * are called
"HOL.plus" and "HOL.minus"
*)

signature CANCEL_DIV_MOD_DATA =
sig
  (*abstract syntax*)
  val div_name: string
  val mod_name: string
  val mk_binop: string -> term * term -> term
  val mk_sum: term list -> term
  val dest_sum: term -> term list
  (*logic*)
  val div_mod_eqs: thm list
  (* (n*(m div n) + m mod n) + k == m + k and
     ((m div n)*n + m mod n) + k == m + k *)
  val prove_eq_sums: simpset -> term * term -> thm
  (* must prove ac0-equivalence of sums *)
end;

signature CANCEL_DIV_MOD =
sig
  val proc: simpset -> term -> thm option
end;


functor CancelDivModFun(Data: CANCEL_DIV_MOD_DATA): CANCEL_DIV_MOD =
struct

fun coll_div_mod (Const("HOL.plus",_) $ s $ t) dms =
      coll_div_mod t (coll_div_mod s dms)
  | coll_div_mod (Const("HOL.times",_) $ m $ (Const(d,_) $ s $ n))
                 (dms as (divs,mods)) =
      if d = Data.div_name andalso m=n then ((s,n)::divs,mods) else dms
  | coll_div_mod (Const("HOL.times",_) $ (Const(d,_) $ s $ n) $ m)
                 (dms as (divs,mods)) =
      if d = Data.div_name andalso m=n then ((s,n)::divs,mods) else dms
  | coll_div_mod (Const(m,_) $ s $ n) (dms as (divs,mods)) =
      if m = Data.mod_name then (divs,(s,n)::mods) else dms
  | coll_div_mod _ dms = dms;


(* Proof principle:
   1. (...div...)+(...mod...) == (div + mod) + rest
      in function rearrange
   2. (div + mod) + ?x = d + ?x
      Data.div_mod_eq
   ==> thesis by transitivity
*)

val mk_plus = Data.mk_binop "HOL.plus"
val mk_times = Data.mk_binop "HOL.times"

fun rearrange t pq =
  let val ts = Data.dest_sum t;
      val dpq = Data.mk_binop Data.div_name pq
      val d1 = mk_times (snd pq,dpq) and d2 = mk_times (dpq,snd pq)
      val d = if d1 mem ts then d1 else d2
      val m = Data.mk_binop Data.mod_name pq
  in mk_plus(mk_plus(d,m),Data.mk_sum(ts \ d \ m)) end

fun cancel ss t pq =
  let val teqt' = Data.prove_eq_sums ss (t, rearrange t pq)
  in hd(Data.div_mod_eqs RL [teqt' RS transitive_thm]) end;

fun proc ss t =
  let val (divs,mods) = coll_div_mod t ([],[])
  in if null divs orelse null mods then NONE
     else case divs inter mods of
            pq :: _ => SOME (cancel ss t pq)
          | [] => NONE
  end

end