src/HOL/Tools/lin_arith.ML
changeset 24328 83afe527504d
parent 24271 499608101177
child 24920 2a45e400fdad
equal deleted inserted replaced
24327:a207114007c6 24328:83afe527504d
   138 
   138 
   139 
   139 
   140 (* Decomposition of terms *)
   140 (* Decomposition of terms *)
   141 
   141 
   142 (*internal representation of linear (in-)equations*)
   142 (*internal representation of linear (in-)equations*)
   143 type decompT = ((term * Rat.rat) list * Rat.rat * string * (term * Rat.rat) list * Rat.rat * bool);
   143 type decompT =
       
   144   ((term * Rat.rat) list * Rat.rat * string * (term * Rat.rat) list * Rat.rat * bool);
   144 
   145 
   145 fun nT (Type ("fun", [N, _])) = (N = HOLogic.natT)
   146 fun nT (Type ("fun", [N, _])) = (N = HOLogic.natT)
   146   | nT _                      = false;
   147   | nT _                      = false;
   147 
   148 
   148 fun add_atom (t : term) (m : Rat.rat) (p : (term * Rat.rat) list, i : Rat.rat) :
   149 fun add_atom (t : term) (m : Rat.rat) (p : (term * Rat.rat) list, i : Rat.rat) :
   149              (term * Rat.rat) list * Rat.rat =
   150              (term * Rat.rat) list * Rat.rat =
   150   case AList.lookup (op =) p t of NONE   => ((t, m) :: p, i)
   151   case AList.lookup (op =) p t of
   151                                 | SOME n => (AList.update (op =) (t, Rat.add n m) p, i);
   152       NONE   => ((t, m) :: p, i)
   152 
   153     | SOME n => (AList.update (op =) (t, Rat.add n m) p, i);
   153 exception Zero;
   154 
   154 
   155 (* decompose nested multiplications, bracketing them to the right and combining
   155 fun rat_of_term (numt, dent) =
   156    all their coefficients
   156   let
   157 
   157     val num = HOLogic.dest_numeral numt
   158    inj_consts: list of constants to be ignored when encountered
   158     val den = HOLogic.dest_numeral dent
   159                (e.g. arithmetic type conversions that preserve value)
   159   in
   160 
   160     if den = 0 then raise Zero else Rat.rat_of_quotient (num, den)
   161    m: multiplicity associated with the entire product
   161   end;
   162 
   162 
   163    returns either (SOME term, associated multiplicity) or (NONE, constant)
   163 (*Warning: in rare cases number_of encloses a non-numeral,
   164 *)
   164   in which case dest_numeral raises TERM; hence all the handles below.
       
   165   Same for Suc-terms that turn out not to be numerals -
       
   166   although the simplifier should eliminate those anyway ...*)
       
   167 fun number_of_Sucs (Const ("Suc", _) $ n) : int =
       
   168       number_of_Sucs n + 1
       
   169   | number_of_Sucs t =
       
   170       if HOLogic.is_zero t then 0 else raise TERM ("number_of_Sucs", []);
       
   171 
       
   172 (*decompose nested multiplications, bracketing them to the right and combining
       
   173   all their coefficients*)
       
   174 fun demult (inj_consts : (string * typ) list) : term * Rat.rat -> term option * Rat.rat =
   165 fun demult (inj_consts : (string * typ) list) : term * Rat.rat -> term option * Rat.rat =
   175 let
   166 let
   176   fun demult ((mC as Const (@{const_name HOL.times}, _)) $ s $ t, m) = (
   167   fun demult ((mC as Const (@{const_name HOL.times}, _)) $ s $ t, m) =
   177     (case s of
   168       (case s of Const (@{const_name HOL.times}, _) $ s1 $ s2 =>
   178       Const ("Numeral.number_class.number_of", _) $ n =>
   169         (* bracketing to the right: '(s1 * s2) * t' becomes 's1 * (s2 * t)' *)
   179         demult (t, Rat.mult m (Rat.rat_of_int (HOLogic.dest_numeral n)))
       
   180     | Const (@{const_name HOL.uminus}, _) $ (Const ("Numeral.number_class.number_of", _) $ n) =>
       
   181         demult (t, Rat.mult m (Rat.rat_of_int (~(HOLogic.dest_numeral n))))
       
   182     | Const (@{const_name Suc}, _) $ _ =>
       
   183         demult (t, Rat.mult m (Rat.rat_of_int (HOLogic.dest_nat s)))
       
   184     | Const (@{const_name HOL.times}, _) $ s1 $ s2 =>
       
   185         demult (mC $ s1 $ (mC $ s2 $ t), m)
   170         demult (mC $ s1 $ (mC $ s2 $ t), m)
   186     | Const (@{const_name HOL.divide}, _) $ numt $
   171       | _ =>
   187           (Const ("Numeral.number_class.number_of", _) $ dent) =>
   172         (* product 's * t', where either factor can be 'NONE' *)
   188         let
   173         (case demult (s, m) of
   189           val den = HOLogic.dest_numeral dent
   174           (SOME s', m') =>
   190         in
   175             (case demult (t, m') of
   191           if den = 0 then
   176               (SOME t', m'') => (SOME (mC $ s' $ t'), m'')
   192             raise Zero
   177             | (NONE,    m'') => (SOME s', m''))
   193           else
   178         | (NONE,    m') => demult (t, m')))
   194             demult (mC $ numt $ t, Rat.mult m (Rat.inv (Rat.rat_of_int den)))
   179     | demult ((mC as Const (@{const_name HOL.divide}, _)) $ s $ t, m) =
   195         end
   180       (* FIXME: Shouldn't we simplify nested quotients, e.g. '(s/t)/u' could
   196     | _ =>
   181          become 's/(t*u)', and '(s*t)/u' could become 's*(t/u)' ?   Note that
   197         atomult (mC, s, t, m)
   182          if we choose to do so here, the simpset used by arith must be able to
   198     ) handle TERM _ => atomult (mC, s, t, m)
   183          perform the same simplifications. *)
   199   )
   184       (* FIXME: Currently we treat the numerator as atomic unless the
   200     | demult (atom as Const(@{const_name HOL.divide}, _) $ t $
   185          denominator can be reduced to a numeric constant.  It might be better
   201         (Const ("Numeral.number_class.number_of", _) $ dent), m) =
   186          to demult the numerator in any case, and invent a new term of the form
   202       (let
   187          '1 / t' if the numerator can be reduced, but the denominator cannot. *)
   203         val den = HOLogic.dest_numeral dent
   188       (* FIXME: Currently we even treat the whole fraction as atomic unless the
   204       in
   189          denominator can be reduced to a numeric constant.  It might be better
   205         if den = 0 then
   190          to use the partially reduced denominator (i.e. 's / (2* t)' could be
   206           raise Zero
   191          demult'ed to 's / t' with multiplicity .5).   This would require a
   207         else
   192          very simple change only below, but it breaks existing proofs. *)
   208           demult (t, Rat.mult m (Rat.inv (Rat.rat_of_int den)))
   193       (* quotient 's / t', where the denominator t can be NONE *)
   209       end handle TERM _ => (SOME atom, m))
   194       (* Note: will raise Rat.DIVZERO iff m' is Rat.zero *)
       
   195       (case demult (t, Rat.one) of
       
   196         (SOME _, _) => (SOME (mC $ s $ t), m)
       
   197       | (NONE,  m') => apsnd (Rat.mult (Rat.inv m')) (demult (s, m)))
       
   198     (* terms that evaluate to numeric constants *)
       
   199     | demult (Const (@{const_name HOL.uminus}, _) $ t, m) = demult (t, Rat.neg m)
   210     | demult (Const (@{const_name HOL.zero}, _), m) = (NONE, Rat.zero)
   200     | demult (Const (@{const_name HOL.zero}, _), m) = (NONE, Rat.zero)
   211     | demult (Const (@{const_name HOL.one}, _), m) = (NONE, m)
   201     | demult (Const (@{const_name HOL.one}, _), m) = (NONE, m)
       
   202     (*Warning: in rare cases number_of encloses a non-numeral,
       
   203       in which case dest_numeral raises TERM; hence all the handles below.
       
   204       Same for Suc-terms that turn out not to be numerals -
       
   205       although the simplifier should eliminate those anyway ...*)
   212     | demult (t as Const ("Numeral.number_class.number_of", _) $ n, m) =
   206     | demult (t as Const ("Numeral.number_class.number_of", _) $ n, m) =
   213         ((NONE, Rat.mult m (Rat.rat_of_int (HOLogic.dest_numeral n)))
   207       ((NONE, Rat.mult m (Rat.rat_of_int (HOLogic.dest_numeral n)))
   214           handle TERM _ => (SOME t, m))
   208         handle TERM _ => (SOME t, m))
   215     | demult (Const (@{const_name HOL.uminus}, _) $ t, m) = demult (t, Rat.neg m)
   209     | demult (t as Const (@{const_name Suc}, _) $ _, m) =
       
   210       ((NONE, Rat.mult m (Rat.rat_of_int (HOLogic.dest_nat t)))
       
   211         handle TERM _ => (SOME t, m))
       
   212     (* injection constants are ignored *)
   216     | demult (t as Const f $ x, m) =
   213     | demult (t as Const f $ x, m) =
   217         (if member (op =) inj_consts f then SOME x else SOME t, m)
   214       if member (op =) inj_consts f then demult (x, m) else (SOME t, m)
       
   215     (* everything else is considered atomic *)
   218     | demult (atom, m) = (SOME atom, m)
   216     | demult (atom, m) = (SOME atom, m)
   219 and
       
   220   atomult (mC, atom, t, m) = (
       
   221     case demult (t, m) of (NONE, m')    => (SOME atom, m')
       
   222                         | (SOME t', m') => (SOME (mC $ atom $ t'), m')
       
   223   )
       
   224 in demult end;
   217 in demult end;
   225 
   218 
   226 fun decomp0 (inj_consts : (string * typ) list) (rel : string, lhs : term, rhs : term) :
   219 fun decomp0 (inj_consts : (string * typ) list) (rel : string, lhs : term, rhs : term) :
   227             ((term * Rat.rat) list * Rat.rat * string * (term * Rat.rat) list * Rat.rat) option =
   220             ((term * Rat.rat) list * Rat.rat * string * (term * Rat.rat) list * Rat.rat) option =
   228 let
   221 let
   229   (* Turn term into list of summand * multiplicity plus a constant *)
   222   (* Turns a term 'all' and associated multiplicity 'm' into a list 'p' of
       
   223      summands and associated multiplicities, plus a constant 'i' (with implicit
       
   224      multiplicity 1) *)
   230   fun poly (Const (@{const_name HOL.plus}, _) $ s $ t,
   225   fun poly (Const (@{const_name HOL.plus}, _) $ s $ t,
   231         m : Rat.rat, pi : (term * Rat.rat) list * Rat.rat) = poly (s, m, poly (t, m, pi))
   226         m : Rat.rat, pi : (term * Rat.rat) list * Rat.rat) = poly (s, m, poly (t, m, pi))
   232     | poly (all as Const (@{const_name HOL.minus}, T) $ s $ t, m, pi) =
   227     | poly (all as Const (@{const_name HOL.minus}, T) $ s $ t, m, pi) =
   233         if nT T then add_atom all m pi else poly (s, m, poly (t, Rat.neg m, pi))
   228         if nT T then add_atom all m pi else poly (s, m, poly (t, Rat.neg m, pi))
   234     | poly (all as Const (@{const_name HOL.uminus}, T) $ t, m, pi) =
   229     | poly (all as Const (@{const_name HOL.uminus}, T) $ t, m, pi) =
   262   case rel of
   257   case rel of
   263     @{const_name HOL.less}    => SOME (p, i, "<", q, j)
   258     @{const_name HOL.less}    => SOME (p, i, "<", q, j)
   264   | @{const_name HOL.less_eq} => SOME (p, i, "<=", q, j)
   259   | @{const_name HOL.less_eq} => SOME (p, i, "<=", q, j)
   265   | "op ="              => SOME (p, i, "=", q, j)
   260   | "op ="              => SOME (p, i, "=", q, j)
   266   | _                   => NONE
   261   | _                   => NONE
   267 end handle Zero => NONE;
   262 end handle Rat.DIVZERO => NONE;
   268 
   263 
   269 fun of_lin_arith_sort thy U =
   264 fun of_lin_arith_sort thy U =
   270   Sign.of_sort thy (U, ["Ring_and_Field.ordered_idom"]);
   265   Sign.of_sort thy (U, ["Ring_and_Field.ordered_idom"]);
   271 
   266 
   272 fun allows_lin_arith sg (discrete : string list) (U as Type (D, [])) : bool * bool =
   267 fun allows_lin_arith sg (discrete : string list) (U as Type (D, [])) : bool * bool =