src/HOL/Tools/lin_arith.ML
changeset 34974 18b41bba42b5
parent 33728 cb4235333c30
child 35028 108662d50512
equal deleted inserted replaced
34973:ae634fad947e 34974:18b41bba42b5
   136 
   136 
   137    returns either (SOME term, associated multiplicity) or (NONE, constant)
   137    returns either (SOME term, associated multiplicity) or (NONE, constant)
   138 *)
   138 *)
   139 fun demult (inj_consts : (string * typ) list) : term * Rat.rat -> term option * Rat.rat =
   139 fun demult (inj_consts : (string * typ) list) : term * Rat.rat -> term option * Rat.rat =
   140 let
   140 let
   141   fun demult ((mC as Const (@{const_name HOL.times}, _)) $ s $ t, m) =
   141   fun demult ((mC as Const (@{const_name Algebras.times}, _)) $ s $ t, m) =
   142       (case s of Const (@{const_name HOL.times}, _) $ s1 $ s2 =>
   142       (case s of Const (@{const_name Algebras.times}, _) $ s1 $ s2 =>
   143         (* bracketing to the right: '(s1 * s2) * t' becomes 's1 * (s2 * t)' *)
   143         (* bracketing to the right: '(s1 * s2) * t' becomes 's1 * (s2 * t)' *)
   144         demult (mC $ s1 $ (mC $ s2 $ t), m)
   144         demult (mC $ s1 $ (mC $ s2 $ t), m)
   145       | _ =>
   145       | _ =>
   146         (* product 's * t', where either factor can be 'NONE' *)
   146         (* product 's * t', where either factor can be 'NONE' *)
   147         (case demult (s, m) of
   147         (case demult (s, m) of
   148           (SOME s', m') =>
   148           (SOME s', m') =>
   149             (case demult (t, m') of
   149             (case demult (t, m') of
   150               (SOME t', m'') => (SOME (mC $ s' $ t'), m'')
   150               (SOME t', m'') => (SOME (mC $ s' $ t'), m'')
   151             | (NONE,    m'') => (SOME s', m''))
   151             | (NONE,    m'') => (SOME s', m''))
   152         | (NONE,    m') => demult (t, m')))
   152         | (NONE,    m') => demult (t, m')))
   153     | demult ((mC as Const (@{const_name HOL.divide}, _)) $ s $ t, m) =
   153     | demult ((mC as Const (@{const_name Algebras.divide}, _)) $ s $ t, m) =
   154       (* FIXME: Shouldn't we simplify nested quotients, e.g. '(s/t)/u' could
   154       (* FIXME: Shouldn't we simplify nested quotients, e.g. '(s/t)/u' could
   155          become 's/(t*u)', and '(s*t)/u' could become 's*(t/u)' ?   Note that
   155          become 's/(t*u)', and '(s*t)/u' could become 's*(t/u)' ?   Note that
   156          if we choose to do so here, the simpset used by arith must be able to
   156          if we choose to do so here, the simpset used by arith must be able to
   157          perform the same simplifications. *)
   157          perform the same simplifications. *)
   158       (* FIXME: Currently we treat the numerator as atomic unless the
   158       (* FIXME: Currently we treat the numerator as atomic unless the
   168       (* Note: will raise Rat.DIVZERO iff m' is Rat.zero *)
   168       (* Note: will raise Rat.DIVZERO iff m' is Rat.zero *)
   169       (case demult (t, Rat.one) of
   169       (case demult (t, Rat.one) of
   170         (SOME _, _) => (SOME (mC $ s $ t), m)
   170         (SOME _, _) => (SOME (mC $ s $ t), m)
   171       | (NONE,  m') => apsnd (Rat.mult (Rat.inv m')) (demult (s, m)))
   171       | (NONE,  m') => apsnd (Rat.mult (Rat.inv m')) (demult (s, m)))
   172     (* terms that evaluate to numeric constants *)
   172     (* terms that evaluate to numeric constants *)
   173     | demult (Const (@{const_name HOL.uminus}, _) $ t, m) = demult (t, Rat.neg m)
   173     | demult (Const (@{const_name Algebras.uminus}, _) $ t, m) = demult (t, Rat.neg m)
   174     | demult (Const (@{const_name HOL.zero}, _), m) = (NONE, Rat.zero)
   174     | demult (Const (@{const_name Algebras.zero}, _), m) = (NONE, Rat.zero)
   175     | demult (Const (@{const_name HOL.one}, _), m) = (NONE, m)
   175     | demult (Const (@{const_name Algebras.one}, _), m) = (NONE, m)
   176     (*Warning: in rare cases number_of encloses a non-numeral,
   176     (*Warning: in rare cases number_of encloses a non-numeral,
   177       in which case dest_numeral raises TERM; hence all the handles below.
   177       in which case dest_numeral raises TERM; hence all the handles below.
   178       Same for Suc-terms that turn out not to be numerals -
   178       Same for Suc-terms that turn out not to be numerals -
   179       although the simplifier should eliminate those anyway ...*)
   179       although the simplifier should eliminate those anyway ...*)
   180     | demult (t as Const ("Int.number_class.number_of", _) $ n, m) =
   180     | demult (t as Const ("Int.number_class.number_of", _) $ n, m) =
   194             ((term * Rat.rat) list * Rat.rat * string * (term * Rat.rat) list * Rat.rat) option =
   194             ((term * Rat.rat) list * Rat.rat * string * (term * Rat.rat) list * Rat.rat) option =
   195 let
   195 let
   196   (* Turns a term 'all' and associated multiplicity 'm' into a list 'p' of
   196   (* Turns a term 'all' and associated multiplicity 'm' into a list 'p' of
   197      summands and associated multiplicities, plus a constant 'i' (with implicit
   197      summands and associated multiplicities, plus a constant 'i' (with implicit
   198      multiplicity 1) *)
   198      multiplicity 1) *)
   199   fun poly (Const (@{const_name HOL.plus}, _) $ s $ t,
   199   fun poly (Const (@{const_name Algebras.plus}, _) $ s $ t,
   200         m : Rat.rat, pi : (term * Rat.rat) list * Rat.rat) = poly (s, m, poly (t, m, pi))
   200         m : Rat.rat, pi : (term * Rat.rat) list * Rat.rat) = poly (s, m, poly (t, m, pi))
   201     | poly (all as Const (@{const_name HOL.minus}, T) $ s $ t, m, pi) =
   201     | poly (all as Const (@{const_name Algebras.minus}, T) $ s $ t, m, pi) =
   202         if nT T then add_atom all m pi else poly (s, m, poly (t, Rat.neg m, pi))
   202         if nT T then add_atom all m pi else poly (s, m, poly (t, Rat.neg m, pi))
   203     | poly (all as Const (@{const_name HOL.uminus}, T) $ t, m, pi) =
   203     | poly (all as Const (@{const_name Algebras.uminus}, T) $ t, m, pi) =
   204         if nT T then add_atom all m pi else poly (t, Rat.neg m, pi)
   204         if nT T then add_atom all m pi else poly (t, Rat.neg m, pi)
   205     | poly (Const (@{const_name HOL.zero}, _), _, pi) =
   205     | poly (Const (@{const_name Algebras.zero}, _), _, pi) =
   206         pi
   206         pi
   207     | poly (Const (@{const_name HOL.one}, _), m, (p, i)) =
   207     | poly (Const (@{const_name Algebras.one}, _), m, (p, i)) =
   208         (p, Rat.add i m)
   208         (p, Rat.add i m)
   209     | poly (Const (@{const_name Suc}, _) $ t, m, (p, i)) =
   209     | poly (Const (@{const_name Suc}, _) $ t, m, (p, i)) =
   210         poly (t, m, (p, Rat.add i m))
   210         poly (t, m, (p, Rat.add i m))
   211     | poly (all as Const (@{const_name HOL.times}, _) $ _ $ _, m, pi as (p, i)) =
   211     | poly (all as Const (@{const_name Algebras.times}, _) $ _ $ _, m, pi as (p, i)) =
   212         (case demult inj_consts (all, m) of
   212         (case demult inj_consts (all, m) of
   213            (NONE,   m') => (p, Rat.add i m')
   213            (NONE,   m') => (p, Rat.add i m')
   214          | (SOME u, m') => add_atom u m' pi)
   214          | (SOME u, m') => add_atom u m' pi)
   215     | poly (all as Const (@{const_name HOL.divide}, _) $ _ $ _, m, pi as (p, i)) =
   215     | poly (all as Const (@{const_name Algebras.divide}, _) $ _ $ _, m, pi as (p, i)) =
   216         (case demult inj_consts (all, m) of
   216         (case demult inj_consts (all, m) of
   217            (NONE,   m') => (p, Rat.add i m')
   217            (NONE,   m') => (p, Rat.add i m')
   218          | (SOME u, m') => add_atom u m' pi)
   218          | (SOME u, m') => add_atom u m' pi)
   219     | poly (all as Const ("Int.number_class.number_of", Type(_,[_,T])) $ t, m, pi as (p, i)) =
   219     | poly (all as Const ("Int.number_class.number_of", Type(_,[_,T])) $ t, m, pi as (p, i)) =
   220         (let val k = HOLogic.dest_numeral t
   220         (let val k = HOLogic.dest_numeral t
   227         add_atom all m pi
   227         add_atom all m pi
   228   val (p, i) = poly (lhs, Rat.one, ([], Rat.zero))
   228   val (p, i) = poly (lhs, Rat.one, ([], Rat.zero))
   229   val (q, j) = poly (rhs, Rat.one, ([], Rat.zero))
   229   val (q, j) = poly (rhs, Rat.one, ([], Rat.zero))
   230 in
   230 in
   231   case rel of
   231   case rel of
   232     @{const_name HOL.less}    => SOME (p, i, "<", q, j)
   232     @{const_name Algebras.less}    => SOME (p, i, "<", q, j)
   233   | @{const_name HOL.less_eq} => SOME (p, i, "<=", q, j)
   233   | @{const_name Algebras.less_eq} => SOME (p, i, "<=", q, j)
   234   | "op ="              => SOME (p, i, "=", q, j)
   234   | "op ="              => SOME (p, i, "=", q, j)
   235   | _                   => NONE
   235   | _                   => NONE
   236 end handle Rat.DIVZERO => NONE;
   236 end handle Rat.DIVZERO => NONE;
   237 
   237 
   238 fun of_lin_arith_sort thy U =
   238 fun of_lin_arith_sort thy U =
   290   case concl_of thm of _ $ (_ $ (_ $ lhs) $ _) => (
   290   case concl_of thm of _ $ (_ $ (_ $ lhs) $ _) => (
   291     (* Trueprop $ ((op =) $ (?P $ lhs) $ rhs) *)
   291     (* Trueprop $ ((op =) $ (?P $ lhs) $ rhs) *)
   292     case head_of lhs of
   292     case head_of lhs of
   293       Const (a, _) => member (op =) [@{const_name Orderings.max},
   293       Const (a, _) => member (op =) [@{const_name Orderings.max},
   294                                     @{const_name Orderings.min},
   294                                     @{const_name Orderings.min},
   295                                     @{const_name HOL.abs},
   295                                     @{const_name Algebras.abs},
   296                                     @{const_name HOL.minus},
   296                                     @{const_name Algebras.minus},
   297                                     "Int.nat",
   297                                     "Int.nat" (*DYNAMIC BINDING!*),
   298                                     "Divides.div_class.mod",
   298                                     "Divides.div_class.mod" (*DYNAMIC BINDING!*),
   299                                     "Divides.div_class.div"] a
   299                                     "Divides.div_class.div" (*DYNAMIC BINDING!*)] a
   300     | _            => (warning ("Lin. Arith.: wrong format for split rule " ^
   300     | _            => (warning ("Lin. Arith.: wrong format for split rule " ^
   301                                  Display.string_of_thm_without_context thm);
   301                                  Display.string_of_thm_without_context thm);
   302                        false))
   302                        false))
   303   | _ => (warning ("Lin. Arith.: wrong format for split rule " ^
   303   | _ => (warning ("Lin. Arith.: wrong format for split rule " ^
   304                    Display.string_of_thm_without_context thm);
   304                    Display.string_of_thm_without_context thm);
   370       (Const (@{const_name Orderings.max}, _), [t1, t2]) =>
   370       (Const (@{const_name Orderings.max}, _), [t1, t2]) =>
   371       let
   371       let
   372         val rev_terms     = rev terms
   372         val rev_terms     = rev terms
   373         val terms1        = map (subst_term [(split_term, t1)]) rev_terms
   373         val terms1        = map (subst_term [(split_term, t1)]) rev_terms
   374         val terms2        = map (subst_term [(split_term, t2)]) rev_terms
   374         val terms2        = map (subst_term [(split_term, t2)]) rev_terms
   375         val t1_leq_t2     = Const (@{const_name HOL.less_eq},
   375         val t1_leq_t2     = Const (@{const_name Algebras.less_eq},
   376                                     split_type --> split_type --> HOLogic.boolT) $ t1 $ t2
   376                                     split_type --> split_type --> HOLogic.boolT) $ t1 $ t2
   377         val not_t1_leq_t2 = HOLogic.Not $ t1_leq_t2
   377         val not_t1_leq_t2 = HOLogic.Not $ t1_leq_t2
   378         val not_false     = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   378         val not_false     = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   379         val subgoal1      = (HOLogic.mk_Trueprop t1_leq_t2) :: terms2 @ [not_false]
   379         val subgoal1      = (HOLogic.mk_Trueprop t1_leq_t2) :: terms2 @ [not_false]
   380         val subgoal2      = (HOLogic.mk_Trueprop not_t1_leq_t2) :: terms1 @ [not_false]
   380         val subgoal2      = (HOLogic.mk_Trueprop not_t1_leq_t2) :: terms1 @ [not_false]
   385     | (Const (@{const_name Orderings.min}, _), [t1, t2]) =>
   385     | (Const (@{const_name Orderings.min}, _), [t1, t2]) =>
   386       let
   386       let
   387         val rev_terms     = rev terms
   387         val rev_terms     = rev terms
   388         val terms1        = map (subst_term [(split_term, t1)]) rev_terms
   388         val terms1        = map (subst_term [(split_term, t1)]) rev_terms
   389         val terms2        = map (subst_term [(split_term, t2)]) rev_terms
   389         val terms2        = map (subst_term [(split_term, t2)]) rev_terms
   390         val t1_leq_t2     = Const (@{const_name HOL.less_eq},
   390         val t1_leq_t2     = Const (@{const_name Algebras.less_eq},
   391                                     split_type --> split_type --> HOLogic.boolT) $ t1 $ t2
   391                                     split_type --> split_type --> HOLogic.boolT) $ t1 $ t2
   392         val not_t1_leq_t2 = HOLogic.Not $ t1_leq_t2
   392         val not_t1_leq_t2 = HOLogic.Not $ t1_leq_t2
   393         val not_false     = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   393         val not_false     = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   394         val subgoal1      = (HOLogic.mk_Trueprop t1_leq_t2) :: terms1 @ [not_false]
   394         val subgoal1      = (HOLogic.mk_Trueprop t1_leq_t2) :: terms1 @ [not_false]
   395         val subgoal2      = (HOLogic.mk_Trueprop not_t1_leq_t2) :: terms2 @ [not_false]
   395         val subgoal2      = (HOLogic.mk_Trueprop not_t1_leq_t2) :: terms2 @ [not_false]
   396       in
   396       in
   397         SOME [(Ts, subgoal1), (Ts, subgoal2)]
   397         SOME [(Ts, subgoal1), (Ts, subgoal2)]
   398       end
   398       end
   399     (* ?P (abs ?a) = ((0 <= ?a --> ?P ?a) & (?a < 0 --> ?P (- ?a))) *)
   399     (* ?P (abs ?a) = ((0 <= ?a --> ?P ?a) & (?a < 0 --> ?P (- ?a))) *)
   400     | (Const (@{const_name HOL.abs}, _), [t1]) =>
   400     | (Const (@{const_name Algebras.abs}, _), [t1]) =>
   401       let
   401       let
   402         val rev_terms   = rev terms
   402         val rev_terms   = rev terms
   403         val terms1      = map (subst_term [(split_term, t1)]) rev_terms
   403         val terms1      = map (subst_term [(split_term, t1)]) rev_terms
   404         val terms2      = map (subst_term [(split_term, Const (@{const_name HOL.uminus},
   404         val terms2      = map (subst_term [(split_term, Const (@{const_name Algebras.uminus},
   405                             split_type --> split_type) $ t1)]) rev_terms
   405                             split_type --> split_type) $ t1)]) rev_terms
   406         val zero        = Const (@{const_name HOL.zero}, split_type)
   406         val zero        = Const (@{const_name Algebras.zero}, split_type)
   407         val zero_leq_t1 = Const (@{const_name HOL.less_eq},
   407         val zero_leq_t1 = Const (@{const_name Algebras.less_eq},
   408                             split_type --> split_type --> HOLogic.boolT) $ zero $ t1
   408                             split_type --> split_type --> HOLogic.boolT) $ zero $ t1
   409         val t1_lt_zero  = Const (@{const_name HOL.less},
   409         val t1_lt_zero  = Const (@{const_name Algebras.less},
   410                             split_type --> split_type --> HOLogic.boolT) $ t1 $ zero
   410                             split_type --> split_type --> HOLogic.boolT) $ t1 $ zero
   411         val not_false   = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   411         val not_false   = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   412         val subgoal1    = (HOLogic.mk_Trueprop zero_leq_t1) :: terms1 @ [not_false]
   412         val subgoal1    = (HOLogic.mk_Trueprop zero_leq_t1) :: terms1 @ [not_false]
   413         val subgoal2    = (HOLogic.mk_Trueprop t1_lt_zero) :: terms2 @ [not_false]
   413         val subgoal2    = (HOLogic.mk_Trueprop t1_lt_zero) :: terms2 @ [not_false]
   414       in
   414       in
   415         SOME [(Ts, subgoal1), (Ts, subgoal2)]
   415         SOME [(Ts, subgoal1), (Ts, subgoal2)]
   416       end
   416       end
   417     (* ?P (?a - ?b) = ((?a < ?b --> ?P 0) & (ALL d. ?a = ?b + d --> ?P d)) *)
   417     (* ?P (?a - ?b) = ((?a < ?b --> ?P 0) & (ALL d. ?a = ?b + d --> ?P d)) *)
   418     | (Const (@{const_name HOL.minus}, _), [t1, t2]) =>
   418     | (Const (@{const_name Algebras.minus}, _), [t1, t2]) =>
   419       let
   419       let
   420         (* "d" in the above theorem becomes a new bound variable after NNF   *)
   420         (* "d" in the above theorem becomes a new bound variable after NNF   *)
   421         (* transformation, therefore some adjustment of indices is necessary *)
   421         (* transformation, therefore some adjustment of indices is necessary *)
   422         val rev_terms       = rev terms
   422         val rev_terms       = rev terms
   423         val zero            = Const (@{const_name HOL.zero}, split_type)
   423         val zero            = Const (@{const_name Algebras.zero}, split_type)
   424         val d               = Bound 0
   424         val d               = Bound 0
   425         val terms1          = map (subst_term [(split_term, zero)]) rev_terms
   425         val terms1          = map (subst_term [(split_term, zero)]) rev_terms
   426         val terms2          = map (subst_term [(incr_boundvars 1 split_term, d)])
   426         val terms2          = map (subst_term [(incr_boundvars 1 split_term, d)])
   427                                 (map (incr_boundvars 1) rev_terms)
   427                                 (map (incr_boundvars 1) rev_terms)
   428         val t1'             = incr_boundvars 1 t1
   428         val t1'             = incr_boundvars 1 t1
   429         val t2'             = incr_boundvars 1 t2
   429         val t2'             = incr_boundvars 1 t2
   430         val t1_lt_t2        = Const (@{const_name HOL.less},
   430         val t1_lt_t2        = Const (@{const_name Algebras.less},
   431                                 split_type --> split_type --> HOLogic.boolT) $ t1 $ t2
   431                                 split_type --> split_type --> HOLogic.boolT) $ t1 $ t2
   432         val t1_eq_t2_plus_d = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   432         val t1_eq_t2_plus_d = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   433                                 (Const (@{const_name HOL.plus},
   433                                 (Const (@{const_name Algebras.plus},
   434                                   split_type --> split_type --> split_type) $ t2' $ d)
   434                                   split_type --> split_type --> split_type) $ t2' $ d)
   435         val not_false       = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   435         val not_false       = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   436         val subgoal1        = (HOLogic.mk_Trueprop t1_lt_t2) :: terms1 @ [not_false]
   436         val subgoal1        = (HOLogic.mk_Trueprop t1_lt_t2) :: terms1 @ [not_false]
   437         val subgoal2        = (HOLogic.mk_Trueprop t1_eq_t2_plus_d) :: terms2 @ [not_false]
   437         val subgoal2        = (HOLogic.mk_Trueprop t1_eq_t2_plus_d) :: terms2 @ [not_false]
   438       in
   438       in
   440       end
   440       end
   441     (* ?P (nat ?i) = ((ALL n. ?i = of_nat n --> ?P n) & (?i < 0 --> ?P 0)) *)
   441     (* ?P (nat ?i) = ((ALL n. ?i = of_nat n --> ?P n) & (?i < 0 --> ?P 0)) *)
   442     | (Const ("Int.nat", _), [t1]) =>
   442     | (Const ("Int.nat", _), [t1]) =>
   443       let
   443       let
   444         val rev_terms   = rev terms
   444         val rev_terms   = rev terms
   445         val zero_int    = Const (@{const_name HOL.zero}, HOLogic.intT)
   445         val zero_int    = Const (@{const_name Algebras.zero}, HOLogic.intT)
   446         val zero_nat    = Const (@{const_name HOL.zero}, HOLogic.natT)
   446         val zero_nat    = Const (@{const_name Algebras.zero}, HOLogic.natT)
   447         val n           = Bound 0
   447         val n           = Bound 0
   448         val terms1      = map (subst_term [(incr_boundvars 1 split_term, n)])
   448         val terms1      = map (subst_term [(incr_boundvars 1 split_term, n)])
   449                             (map (incr_boundvars 1) rev_terms)
   449                             (map (incr_boundvars 1) rev_terms)
   450         val terms2      = map (subst_term [(split_term, zero_nat)]) rev_terms
   450         val terms2      = map (subst_term [(split_term, zero_nat)]) rev_terms
   451         val t1'         = incr_boundvars 1 t1
   451         val t1'         = incr_boundvars 1 t1
   452         val t1_eq_nat_n = Const ("op =", HOLogic.intT --> HOLogic.intT --> HOLogic.boolT) $ t1' $
   452         val t1_eq_nat_n = Const ("op =", HOLogic.intT --> HOLogic.intT --> HOLogic.boolT) $ t1' $
   453                             (Const (@{const_name of_nat}, HOLogic.natT --> HOLogic.intT) $ n)
   453                             (Const (@{const_name of_nat}, HOLogic.natT --> HOLogic.intT) $ n)
   454         val t1_lt_zero  = Const (@{const_name HOL.less},
   454         val t1_lt_zero  = Const (@{const_name Algebras.less},
   455                             HOLogic.intT --> HOLogic.intT --> HOLogic.boolT) $ t1 $ zero_int
   455                             HOLogic.intT --> HOLogic.intT --> HOLogic.boolT) $ t1 $ zero_int
   456         val not_false   = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   456         val not_false   = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   457         val subgoal1    = (HOLogic.mk_Trueprop t1_eq_nat_n) :: terms1 @ [not_false]
   457         val subgoal1    = (HOLogic.mk_Trueprop t1_eq_nat_n) :: terms1 @ [not_false]
   458         val subgoal2    = (HOLogic.mk_Trueprop t1_lt_zero) :: terms2 @ [not_false]
   458         val subgoal2    = (HOLogic.mk_Trueprop t1_lt_zero) :: terms2 @ [not_false]
   459       in
   459       in
   463          ((number_of ?k = 0 --> ?P ?n) & (~ (number_of ?k = 0) -->
   463          ((number_of ?k = 0 --> ?P ?n) & (~ (number_of ?k = 0) -->
   464            (ALL i j. j < number_of ?k --> ?n = number_of ?k * i + j --> ?P j))) *)
   464            (ALL i j. j < number_of ?k --> ?n = number_of ?k * i + j --> ?P j))) *)
   465     | (Const ("Divides.div_class.mod", Type ("fun", [Type ("nat", []), _])), [t1, t2]) =>
   465     | (Const ("Divides.div_class.mod", Type ("fun", [Type ("nat", []), _])), [t1, t2]) =>
   466       let
   466       let
   467         val rev_terms               = rev terms
   467         val rev_terms               = rev terms
   468         val zero                    = Const (@{const_name HOL.zero}, split_type)
   468         val zero                    = Const (@{const_name Algebras.zero}, split_type)
   469         val i                       = Bound 1
   469         val i                       = Bound 1
   470         val j                       = Bound 0
   470         val j                       = Bound 0
   471         val terms1                  = map (subst_term [(split_term, t1)]) rev_terms
   471         val terms1                  = map (subst_term [(split_term, t1)]) rev_terms
   472         val terms2                  = map (subst_term [(incr_boundvars 2 split_term, j)])
   472         val terms2                  = map (subst_term [(incr_boundvars 2 split_term, j)])
   473                                         (map (incr_boundvars 2) rev_terms)
   473                                         (map (incr_boundvars 2) rev_terms)
   475         val t2'                     = incr_boundvars 2 t2
   475         val t2'                     = incr_boundvars 2 t2
   476         val t2_eq_zero              = Const ("op =",
   476         val t2_eq_zero              = Const ("op =",
   477                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   477                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   478         val t2_neq_zero             = HOLogic.mk_not (Const ("op =",
   478         val t2_neq_zero             = HOLogic.mk_not (Const ("op =",
   479                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero)
   479                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero)
   480         val j_lt_t2                 = Const (@{const_name HOL.less},
   480         val j_lt_t2                 = Const (@{const_name Algebras.less},
   481                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   481                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   482         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   482         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   483                                        (Const (@{const_name HOL.plus}, split_type --> split_type --> split_type) $
   483                                        (Const (@{const_name Algebras.plus}, split_type --> split_type --> split_type) $
   484                                          (Const (@{const_name HOL.times},
   484                                          (Const (@{const_name Algebras.times},
   485                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   485                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   486         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   486         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   487         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   487         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   488         val subgoal2                = (map HOLogic.mk_Trueprop
   488         val subgoal2                = (map HOLogic.mk_Trueprop
   489                                         [t2_neq_zero, j_lt_t2, t1_eq_t2_times_i_plus_j])
   489                                         [t2_neq_zero, j_lt_t2, t1_eq_t2_times_i_plus_j])
   495          ((number_of ?k = 0 --> ?P 0) & (~ (number_of ?k = 0) -->
   495          ((number_of ?k = 0 --> ?P 0) & (~ (number_of ?k = 0) -->
   496            (ALL i j. j < number_of ?k --> ?n = number_of ?k * i + j --> ?P i))) *)
   496            (ALL i j. j < number_of ?k --> ?n = number_of ?k * i + j --> ?P i))) *)
   497     | (Const ("Divides.div_class.div", Type ("fun", [Type ("nat", []), _])), [t1, t2]) =>
   497     | (Const ("Divides.div_class.div", Type ("fun", [Type ("nat", []), _])), [t1, t2]) =>
   498       let
   498       let
   499         val rev_terms               = rev terms
   499         val rev_terms               = rev terms
   500         val zero                    = Const (@{const_name HOL.zero}, split_type)
   500         val zero                    = Const (@{const_name Algebras.zero}, split_type)
   501         val i                       = Bound 1
   501         val i                       = Bound 1
   502         val j                       = Bound 0
   502         val j                       = Bound 0
   503         val terms1                  = map (subst_term [(split_term, zero)]) rev_terms
   503         val terms1                  = map (subst_term [(split_term, zero)]) rev_terms
   504         val terms2                  = map (subst_term [(incr_boundvars 2 split_term, i)])
   504         val terms2                  = map (subst_term [(incr_boundvars 2 split_term, i)])
   505                                         (map (incr_boundvars 2) rev_terms)
   505                                         (map (incr_boundvars 2) rev_terms)
   507         val t2'                     = incr_boundvars 2 t2
   507         val t2'                     = incr_boundvars 2 t2
   508         val t2_eq_zero              = Const ("op =",
   508         val t2_eq_zero              = Const ("op =",
   509                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   509                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   510         val t2_neq_zero             = HOLogic.mk_not (Const ("op =",
   510         val t2_neq_zero             = HOLogic.mk_not (Const ("op =",
   511                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero)
   511                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero)
   512         val j_lt_t2                 = Const (@{const_name HOL.less},
   512         val j_lt_t2                 = Const (@{const_name Algebras.less},
   513                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   513                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   514         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   514         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   515                                        (Const (@{const_name HOL.plus}, split_type --> split_type --> split_type) $
   515                                        (Const (@{const_name Algebras.plus}, split_type --> split_type --> split_type) $
   516                                          (Const (@{const_name HOL.times},
   516                                          (Const (@{const_name Algebras.times},
   517                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   517                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   518         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   518         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   519         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   519         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   520         val subgoal2                = (map HOLogic.mk_Trueprop
   520         val subgoal2                = (map HOLogic.mk_Trueprop
   521                                         [t2_neq_zero, j_lt_t2, t1_eq_t2_times_i_plus_j])
   521                                         [t2_neq_zero, j_lt_t2, t1_eq_t2_times_i_plus_j])
   533               number_of ?k < j & j <= 0 & ?n = number_of ?k * i + j --> ?P j))) *)
   533               number_of ?k < j & j <= 0 & ?n = number_of ?k * i + j --> ?P j))) *)
   534     | (Const ("Divides.div_class.mod",
   534     | (Const ("Divides.div_class.mod",
   535         Type ("fun", [Type ("Int.int", []), _])), [t1, t2]) =>
   535         Type ("fun", [Type ("Int.int", []), _])), [t1, t2]) =>
   536       let
   536       let
   537         val rev_terms               = rev terms
   537         val rev_terms               = rev terms
   538         val zero                    = Const (@{const_name HOL.zero}, split_type)
   538         val zero                    = Const (@{const_name Algebras.zero}, split_type)
   539         val i                       = Bound 1
   539         val i                       = Bound 1
   540         val j                       = Bound 0
   540         val j                       = Bound 0
   541         val terms1                  = map (subst_term [(split_term, t1)]) rev_terms
   541         val terms1                  = map (subst_term [(split_term, t1)]) rev_terms
   542         val terms2_3                = map (subst_term [(incr_boundvars 2 split_term, j)])
   542         val terms2_3                = map (subst_term [(incr_boundvars 2 split_term, j)])
   543                                         (map (incr_boundvars 2) rev_terms)
   543                                         (map (incr_boundvars 2) rev_terms)
   544         val t1'                     = incr_boundvars 2 t1
   544         val t1'                     = incr_boundvars 2 t1
   545         val t2'                     = incr_boundvars 2 t2
   545         val t2'                     = incr_boundvars 2 t2
   546         val t2_eq_zero              = Const ("op =",
   546         val t2_eq_zero              = Const ("op =",
   547                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   547                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   548         val zero_lt_t2              = Const (@{const_name HOL.less},
   548         val zero_lt_t2              = Const (@{const_name Algebras.less},
   549                                         split_type --> split_type --> HOLogic.boolT) $ zero $ t2'
   549                                         split_type --> split_type --> HOLogic.boolT) $ zero $ t2'
   550         val t2_lt_zero              = Const (@{const_name HOL.less},
   550         val t2_lt_zero              = Const (@{const_name Algebras.less},
   551                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero
   551                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero
   552         val zero_leq_j              = Const (@{const_name HOL.less_eq},
   552         val zero_leq_j              = Const (@{const_name Algebras.less_eq},
   553                                         split_type --> split_type --> HOLogic.boolT) $ zero $ j
   553                                         split_type --> split_type --> HOLogic.boolT) $ zero $ j
   554         val j_leq_zero              = Const (@{const_name HOL.less_eq},
   554         val j_leq_zero              = Const (@{const_name Algebras.less_eq},
   555                                         split_type --> split_type --> HOLogic.boolT) $ j $ zero
   555                                         split_type --> split_type --> HOLogic.boolT) $ j $ zero
   556         val j_lt_t2                 = Const (@{const_name HOL.less},
   556         val j_lt_t2                 = Const (@{const_name Algebras.less},
   557                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   557                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   558         val t2_lt_j                 = Const (@{const_name HOL.less},
   558         val t2_lt_j                 = Const (@{const_name Algebras.less},
   559                                         split_type --> split_type--> HOLogic.boolT) $ t2' $ j
   559                                         split_type --> split_type--> HOLogic.boolT) $ t2' $ j
   560         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   560         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   561                                        (Const (@{const_name HOL.plus}, split_type --> split_type --> split_type) $
   561                                        (Const (@{const_name Algebras.plus}, split_type --> split_type --> split_type) $
   562                                          (Const (@{const_name HOL.times},
   562                                          (Const (@{const_name Algebras.times},
   563                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   563                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   564         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   564         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   565         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   565         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   566         val subgoal2                = (map HOLogic.mk_Trueprop [zero_lt_t2, zero_leq_j])
   566         val subgoal2                = (map HOLogic.mk_Trueprop [zero_lt_t2, zero_leq_j])
   567                                         @ hd terms2_3
   567                                         @ hd terms2_3
   587               number_of ?k < j & j <= 0 & ?n = number_of ?k * i + j --> ?P i))) *)
   587               number_of ?k < j & j <= 0 & ?n = number_of ?k * i + j --> ?P i))) *)
   588     | (Const ("Divides.div_class.div",
   588     | (Const ("Divides.div_class.div",
   589         Type ("fun", [Type ("Int.int", []), _])), [t1, t2]) =>
   589         Type ("fun", [Type ("Int.int", []), _])), [t1, t2]) =>
   590       let
   590       let
   591         val rev_terms               = rev terms
   591         val rev_terms               = rev terms
   592         val zero                    = Const (@{const_name HOL.zero}, split_type)
   592         val zero                    = Const (@{const_name Algebras.zero}, split_type)
   593         val i                       = Bound 1
   593         val i                       = Bound 1
   594         val j                       = Bound 0
   594         val j                       = Bound 0
   595         val terms1                  = map (subst_term [(split_term, zero)]) rev_terms
   595         val terms1                  = map (subst_term [(split_term, zero)]) rev_terms
   596         val terms2_3                = map (subst_term [(incr_boundvars 2 split_term, i)])
   596         val terms2_3                = map (subst_term [(incr_boundvars 2 split_term, i)])
   597                                         (map (incr_boundvars 2) rev_terms)
   597                                         (map (incr_boundvars 2) rev_terms)
   598         val t1'                     = incr_boundvars 2 t1
   598         val t1'                     = incr_boundvars 2 t1
   599         val t2'                     = incr_boundvars 2 t2
   599         val t2'                     = incr_boundvars 2 t2
   600         val t2_eq_zero              = Const ("op =",
   600         val t2_eq_zero              = Const ("op =",
   601                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   601                                         split_type --> split_type --> HOLogic.boolT) $ t2 $ zero
   602         val zero_lt_t2              = Const (@{const_name HOL.less},
   602         val zero_lt_t2              = Const (@{const_name Algebras.less},
   603                                         split_type --> split_type --> HOLogic.boolT) $ zero $ t2'
   603                                         split_type --> split_type --> HOLogic.boolT) $ zero $ t2'
   604         val t2_lt_zero              = Const (@{const_name HOL.less},
   604         val t2_lt_zero              = Const (@{const_name Algebras.less},
   605                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero
   605                                         split_type --> split_type --> HOLogic.boolT) $ t2' $ zero
   606         val zero_leq_j              = Const (@{const_name HOL.less_eq},
   606         val zero_leq_j              = Const (@{const_name Algebras.less_eq},
   607                                         split_type --> split_type --> HOLogic.boolT) $ zero $ j
   607                                         split_type --> split_type --> HOLogic.boolT) $ zero $ j
   608         val j_leq_zero              = Const (@{const_name HOL.less_eq},
   608         val j_leq_zero              = Const (@{const_name Algebras.less_eq},
   609                                         split_type --> split_type --> HOLogic.boolT) $ j $ zero
   609                                         split_type --> split_type --> HOLogic.boolT) $ j $ zero
   610         val j_lt_t2                 = Const (@{const_name HOL.less},
   610         val j_lt_t2                 = Const (@{const_name Algebras.less},
   611                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   611                                         split_type --> split_type--> HOLogic.boolT) $ j $ t2'
   612         val t2_lt_j                 = Const (@{const_name HOL.less},
   612         val t2_lt_j                 = Const (@{const_name Algebras.less},
   613                                         split_type --> split_type--> HOLogic.boolT) $ t2' $ j
   613                                         split_type --> split_type--> HOLogic.boolT) $ t2' $ j
   614         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   614         val t1_eq_t2_times_i_plus_j = Const ("op =", split_type --> split_type --> HOLogic.boolT) $ t1' $
   615                                        (Const (@{const_name HOL.plus}, split_type --> split_type --> split_type) $
   615                                        (Const (@{const_name Algebras.plus}, split_type --> split_type --> split_type) $
   616                                          (Const (@{const_name HOL.times},
   616                                          (Const (@{const_name Algebras.times},
   617                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   617                                            split_type --> split_type --> split_type) $ t2' $ i) $ j)
   618         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   618         val not_false               = HOLogic.mk_Trueprop (HOLogic.Not $ HOLogic.false_const)
   619         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   619         val subgoal1                = (HOLogic.mk_Trueprop t2_eq_zero) :: terms1 @ [not_false]
   620         val subgoal2                = (map HOLogic.mk_Trueprop [zero_lt_t2, zero_leq_j])
   620         val subgoal2                = (map HOLogic.mk_Trueprop [zero_lt_t2, zero_leq_j])
   621                                         @ hd terms2_3
   621                                         @ hd terms2_3