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) = |