| author | nipkow | 
| Wed, 03 Jul 2024 19:42:13 +0200 | |
| changeset 80484 | 0ca36dcdcbd3 | 
| parent 80095 | 0f9cd1a5edbe | 
| child 80914 | d97fdabd9e2b | 
| permissions | -rw-r--r-- | 
| 70043 | 1 | (* Author: Andreas Lochbihler, ETH Zurich | 
| 2 | Author: Florian Haftmann, TU Muenchen | |
| 3 | with some material ported from HOL Light by LCP | |
| 4 | *) | |
| 5 | ||
| 6 | section \<open>Polynomial mapping: combination of almost everywhere zero functions with an algebraic view\<close> | |
| 7 | ||
| 8 | theory Poly_Mapping | |
| 9 | imports Groups_Big_Fun Fun_Lexorder More_List | |
| 10 | begin | |
| 11 | ||
| 70045 
7b6add80e3a5
fixed markup in Poly_Mapping; Free_Abelian_Groups (but not yet imported by Algebra!)
 paulson <lp15@cam.ac.uk> parents: 
70043diff
changeset | 12 | subsection \<open>Preliminary: auxiliary operations for \emph{almost everywhere zero}\<close>
 | 
| 70043 | 13 | |
| 14 | text \<open> | |
| 70045 
7b6add80e3a5
fixed markup in Poly_Mapping; Free_Abelian_Groups (but not yet imported by Algebra!)
 paulson <lp15@cam.ac.uk> parents: 
70043diff
changeset | 15 |   A central notion for polynomials are functions being \emph{almost everywhere zero}.
 | 
| 70043 | 16 | For these we provide some auxiliary definitions and lemmas. | 
| 17 | \<close> | |
| 18 | ||
| 19 | lemma finite_mult_not_eq_zero_leftI: | |
| 20 | fixes f :: "'b \<Rightarrow> 'a :: mult_zero" | |
| 21 |   assumes "finite {a. f a \<noteq> 0}"
 | |
| 22 |   shows "finite {a. g a * f a \<noteq> 0}"
 | |
| 23 | proof - | |
| 24 |   have "{a. g a * f a \<noteq> 0} \<subseteq> {a. f a \<noteq> 0}" by auto
 | |
| 25 | then show ?thesis using assms by (rule finite_subset) | |
| 26 | qed | |
| 27 | ||
| 28 | lemma finite_mult_not_eq_zero_rightI: | |
| 29 | fixes f :: "'b \<Rightarrow> 'a :: mult_zero" | |
| 30 |   assumes "finite {a. f a \<noteq> 0}"
 | |
| 31 |   shows "finite {a. f a * g a \<noteq> 0}"
 | |
| 32 | proof - | |
| 33 |   have "{a. f a * g a \<noteq> 0} \<subseteq> {a. f a \<noteq> 0}" by auto
 | |
| 34 | then show ?thesis using assms by (rule finite_subset) | |
| 35 | qed | |
| 36 | ||
| 37 | lemma finite_mult_not_eq_zero_prodI: | |
| 38 | fixes f g :: "'a \<Rightarrow> 'b::semiring_0" | |
| 39 |   assumes "finite {a. f a \<noteq> 0}" (is "finite ?F")
 | |
| 40 |   assumes "finite {b. g b \<noteq> 0}" (is "finite ?G")
 | |
| 41 |   shows "finite {(a, b). f a * g b \<noteq> 0}"
 | |
| 42 | proof - | |
| 43 | from assms have "finite (?F \<times> ?G)" | |
| 44 | by blast | |
| 45 |   then have "finite {(a, b). f a \<noteq> 0 \<and> g b \<noteq> 0}"
 | |
| 46 | by simp | |
| 47 | then show ?thesis | |
| 48 | by (rule rev_finite_subset) auto | |
| 49 | qed | |
| 50 | ||
| 51 | lemma finite_not_eq_zero_sumI: | |
| 52 | fixes f g :: "'a::monoid_add \<Rightarrow> 'b::semiring_0" | |
| 53 |   assumes "finite {a. f a \<noteq> 0}" (is "finite ?F")
 | |
| 54 |   assumes "finite {b. g b \<noteq> 0}" (is "finite ?G")
 | |
| 55 |   shows "finite {a + b | a b. f a \<noteq> 0 \<and> g b \<noteq> 0}" (is "finite ?FG")
 | |
| 56 | proof - | |
| 57 | from assms have "finite (?F \<times> ?G)" | |
| 58 | by (simp add: finite_cartesian_product_iff) | |
| 59 | then have "finite (case_prod plus ` (?F \<times> ?G))" | |
| 60 | by (rule finite_imageI) | |
| 61 | also have "case_prod plus ` (?F \<times> ?G) = ?FG" | |
| 62 | by auto | |
| 63 | finally show ?thesis | |
| 64 | by simp | |
| 65 | qed | |
| 66 | ||
| 67 | lemma finite_mult_not_eq_zero_sumI: | |
| 68 | fixes f g :: "'a::monoid_add \<Rightarrow> 'b::semiring_0" | |
| 69 |   assumes "finite {a. f a \<noteq> 0}"
 | |
| 70 |   assumes "finite {b. g b \<noteq> 0}"
 | |
| 71 |   shows "finite {a + b | a b. f a * g b \<noteq> 0}"
 | |
| 72 | proof - | |
| 73 | from assms | |
| 74 |   have "finite {a + b | a b. f a \<noteq> 0 \<and> g b \<noteq> 0}"
 | |
| 75 | by (rule finite_not_eq_zero_sumI) | |
| 76 | then show ?thesis | |
| 77 | by (rule rev_finite_subset) (auto dest: mult_not_zero) | |
| 78 | qed | |
| 79 | ||
| 80 | lemma finite_Sum_any_not_eq_zero_weakenI: | |
| 81 |   assumes "finite {a. \<exists>b. f a b \<noteq> 0}"
 | |
| 82 |   shows "finite {a. Sum_any (f a) \<noteq> 0}"
 | |
| 83 | proof - | |
| 84 |   have "{a. Sum_any (f a) \<noteq> 0} \<subseteq> {a. \<exists>b. f a b \<noteq> 0}"
 | |
| 85 | by (auto elim: Sum_any.not_neutral_obtains_not_neutral) | |
| 86 | then show ?thesis using assms by (rule finite_subset) | |
| 87 | qed | |
| 88 | ||
| 89 | context zero | |
| 90 | begin | |
| 91 | ||
| 92 | definition "when" :: "'a \<Rightarrow> bool \<Rightarrow> 'a" (infixl "when" 20) | |
| 93 | where | |
| 94 | "(a when P) = (if P then a else 0)" | |
| 95 | ||
| 96 | text \<open> | |
| 97 | Case distinctions always complicate matters, particularly when | |
| 98 |   nested.  The @{const "when"} operation allows to minimise these
 | |
| 99 |   if @{term 0} is the false-case value and makes proof obligations
 | |
| 100 | much more readable. | |
| 101 | \<close> | |
| 102 | ||
| 103 | lemma "when" [simp]: | |
| 104 | "P \<Longrightarrow> (a when P) = a" | |
| 105 | "\<not> P \<Longrightarrow> (a when P) = 0" | |
| 106 | by (simp_all add: when_def) | |
| 107 | ||
| 108 | lemma when_simps [simp]: | |
| 109 | "(a when True) = a" | |
| 110 | "(a when False) = 0" | |
| 111 | by simp_all | |
| 112 | ||
| 113 | lemma when_cong: | |
| 114 | assumes "P \<longleftrightarrow> Q" | |
| 115 | and "Q \<Longrightarrow> a = b" | |
| 116 | shows "(a when P) = (b when Q)" | |
| 117 | using assms by (simp add: when_def) | |
| 118 | ||
| 119 | lemma zero_when [simp]: | |
| 120 | "(0 when P) = 0" | |
| 121 | by (simp add: when_def) | |
| 122 | ||
| 123 | lemma when_when: | |
| 124 | "(a when P when Q) = (a when P \<and> Q)" | |
| 125 | by (cases Q) simp_all | |
| 126 | ||
| 127 | lemma when_commute: | |
| 128 | "(a when Q when P) = (a when P when Q)" | |
| 129 | by (simp add: when_when conj_commute) | |
| 130 | ||
| 131 | lemma when_neq_zero [simp]: | |
| 132 | "(a when P) \<noteq> 0 \<longleftrightarrow> P \<and> a \<noteq> 0" | |
| 133 | by (cases P) simp_all | |
| 134 | ||
| 135 | end | |
| 136 | ||
| 137 | context monoid_add | |
| 138 | begin | |
| 139 | ||
| 140 | lemma when_add_distrib: | |
| 141 | "(a + b when P) = (a when P) + (b when P)" | |
| 142 | by (simp add: when_def) | |
| 143 | ||
| 144 | end | |
| 145 | ||
| 146 | context semiring_1 | |
| 147 | begin | |
| 148 | ||
| 149 | lemma zero_power_eq: | |
| 150 | "0 ^ n = (1 when n = 0)" | |
| 151 | by (simp add: power_0_left) | |
| 152 | ||
| 153 | end | |
| 154 | ||
| 155 | context comm_monoid_add | |
| 156 | begin | |
| 157 | ||
| 158 | lemma Sum_any_when_equal [simp]: | |
| 159 | "(\<Sum>a. (f a when a = b)) = f b" | |
| 160 | by (simp add: when_def) | |
| 161 | ||
| 162 | lemma Sum_any_when_equal' [simp]: | |
| 163 | "(\<Sum>a. (f a when b = a)) = f b" | |
| 164 | by (simp add: when_def) | |
| 165 | ||
| 166 | lemma Sum_any_when_independent: | |
| 167 | "(\<Sum>a. g a when P) = ((\<Sum>a. g a) when P)" | |
| 168 | by (cases P) simp_all | |
| 169 | ||
| 170 | lemma Sum_any_when_dependent_prod_right: | |
| 171 | "(\<Sum>(a, b). g a when b = h a) = (\<Sum>a. g a)" | |
| 172 | proof - | |
| 173 |   have "inj_on (\<lambda>a. (a, h a)) {a. g a \<noteq> 0}"
 | |
| 174 | by (rule inj_onI) auto | |
| 175 | then show ?thesis unfolding Sum_any.expand_set | |
| 176 | by (rule sum.reindex_cong) auto | |
| 177 | qed | |
| 178 | ||
| 179 | lemma Sum_any_when_dependent_prod_left: | |
| 180 | "(\<Sum>(a, b). g b when a = h b) = (\<Sum>b. g b)" | |
| 181 | proof - | |
| 182 | have "(\<Sum>(a, b). g b when a = h b) = (\<Sum>(b, a). g b when a = h b)" | |
| 183 | by (rule Sum_any.reindex_cong [of prod.swap]) (simp_all add: fun_eq_iff) | |
| 184 | then show ?thesis by (simp add: Sum_any_when_dependent_prod_right) | |
| 185 | qed | |
| 186 | ||
| 187 | end | |
| 188 | ||
| 189 | context cancel_comm_monoid_add | |
| 190 | begin | |
| 191 | ||
| 192 | lemma when_diff_distrib: | |
| 193 | "(a - b when P) = (a when P) - (b when P)" | |
| 194 | by (simp add: when_def) | |
| 195 | ||
| 196 | end | |
| 197 | ||
| 198 | context group_add | |
| 199 | begin | |
| 200 | ||
| 201 | lemma when_uminus_distrib: | |
| 202 | "(- a when P) = - (a when P)" | |
| 203 | by (simp add: when_def) | |
| 204 | ||
| 205 | end | |
| 206 | ||
| 207 | context mult_zero | |
| 208 | begin | |
| 209 | ||
| 210 | lemma mult_when: | |
| 211 | "a * (b when P) = (a * b when P)" | |
| 212 | by (cases P) simp_all | |
| 213 | ||
| 214 | lemma when_mult: | |
| 215 | "(a when P) * b = (a * b when P)" | |
| 216 | by (cases P) simp_all | |
| 217 | ||
| 218 | end | |
| 219 | ||
| 220 | ||
| 221 | subsection \<open>Type definition\<close> | |
| 222 | ||
| 223 | text \<open> | |
| 224 | The following type is of central importance: | |
| 225 | \<close> | |
| 226 | ||
| 227 | typedef (overloaded) ('a, 'b) poly_mapping ("(_ \<Rightarrow>\<^sub>0 /_)" [1, 0] 0) =
 | |
| 228 |   "{f :: 'a \<Rightarrow> 'b::zero. finite {x. f x \<noteq> 0}}"
 | |
| 229 | morphisms lookup Abs_poly_mapping | |
| 230 | proof - | |
| 231 | have "(\<lambda>_::'a. (0 :: 'b)) \<in> ?poly_mapping" by simp | |
| 232 | then show ?thesis by (blast intro!: exI) | |
| 233 | qed | |
| 234 | ||
| 235 | declare lookup_inverse [simp] | |
| 236 | declare lookup_inject [simp] | |
| 237 | ||
| 238 | lemma lookup_Abs_poly_mapping [simp]: | |
| 239 |   "finite {x. f x \<noteq> 0} \<Longrightarrow> lookup (Abs_poly_mapping f) = f"
 | |
| 240 | using Abs_poly_mapping_inverse [of f] by simp | |
| 241 | ||
| 242 | lemma finite_lookup [simp]: | |
| 243 |   "finite {k. lookup f k \<noteq> 0}"
 | |
| 244 | using poly_mapping.lookup [of f] by simp | |
| 245 | ||
| 246 | lemma finite_lookup_nat [simp]: | |
| 247 | fixes f :: "'a \<Rightarrow>\<^sub>0 nat" | |
| 248 |   shows "finite {k. 0 < lookup f k}"
 | |
| 249 | using poly_mapping.lookup [of f] by simp | |
| 250 | ||
| 251 | lemma poly_mapping_eqI: | |
| 252 | assumes "\<And>k. lookup f k = lookup g k" | |
| 253 | shows "f = g" | |
| 254 | using assms unfolding poly_mapping.lookup_inject [symmetric] | |
| 255 | by blast | |
| 256 | ||
| 257 | lemma poly_mapping_eq_iff: "a = b \<longleftrightarrow> lookup a = lookup b" | |
| 258 | by auto | |
| 259 | ||
| 260 | text \<open> | |
| 70045 
7b6add80e3a5
fixed markup in Poly_Mapping; Free_Abelian_Groups (but not yet imported by Algebra!)
 paulson <lp15@cam.ac.uk> parents: 
70043diff
changeset | 261 |   We model the universe of functions being \emph{almost everywhere zero}
 | 
| 70043 | 262 |   by means of a separate type @{typ "('a, 'b) poly_mapping"}.
 | 
| 263 | For convenience we provide a suggestive infix syntax which | |
| 264 | is a variant of the usual function space syntax. Conversion between both types | |
| 265 | happens through the morphisms | |
| 266 |   \begin{quote}
 | |
| 267 |     @{term_type lookup}
 | |
| 268 |   \end{quote}
 | |
| 269 |   \begin{quote}
 | |
| 270 |     @{term_type Abs_poly_mapping}
 | |
| 271 |   \end{quote}
 | |
| 272 | satisfying | |
| 273 |   \begin{quote}
 | |
| 274 |     @{thm lookup_inverse}
 | |
| 275 |   \end{quote}
 | |
| 276 |   \begin{quote}
 | |
| 277 |     @{thm lookup_Abs_poly_mapping}
 | |
| 278 |   \end{quote}
 | |
| 279 | Luckily, we have rarely to deal with those low-level morphisms explicitly | |
| 280 |   but rely on Isabelle's \emph{lifting} package with its method \<open>transfer\<close>
 | |
| 281 | and its specification tool \<open>lift_definition\<close>. | |
| 282 | \<close> | |
| 283 | ||
| 284 | setup_lifting type_definition_poly_mapping | |
| 285 | code_datatype Abs_poly_mapping\<comment>\<open>FIXME? workaround for preventing \<open>code_abstype\<close> setup\<close> | |
| 286 | ||
| 287 | text \<open> | |
| 288 |   @{typ "'a \<Rightarrow>\<^sub>0 'b"} serves distinctive purposes:
 | |
| 289 |   \begin{enumerate}
 | |
| 290 |     \item A clever nesting as @{typ "(nat \<Rightarrow>\<^sub>0 nat) \<Rightarrow>\<^sub>0 'a"}
 | |
| 291 | later in theory \<open>MPoly\<close> gives a suitable | |
| 70045 
7b6add80e3a5
fixed markup in Poly_Mapping; Free_Abelian_Groups (but not yet imported by Algebra!)
 paulson <lp15@cam.ac.uk> parents: 
70043diff
changeset | 292 |       representation type for polynomials \emph{almost for free}:
 | 
| 70043 | 293 |       Interpreting @{typ "nat \<Rightarrow>\<^sub>0 nat"} as a mapping from variable identifiers
 | 
| 294 | to exponents yields monomials, and the whole type maps monomials | |
| 295 |       to coefficients.  Lets call this the \emph{ultimate interpretation}.
 | |
| 296 |     \item A further more specialised type isomorphic to @{typ "nat \<Rightarrow>\<^sub>0 'a"}
 | |
| 297 | is apt to direct implementation using code generation | |
| 76987 | 298 | \<^cite>\<open>"Haftmann-Nipkow:2010:code"\<close>. | 
| 70043 | 299 |   \end{enumerate}
 | 
| 70045 
7b6add80e3a5
fixed markup in Poly_Mapping; Free_Abelian_Groups (but not yet imported by Algebra!)
 paulson <lp15@cam.ac.uk> parents: 
70043diff
changeset | 300 |   Note that despite the names \emph{mapping} and \emph{lookup} suggest something
 | 
| 70043 | 301 |   implementation-near, it is best to keep @{typ "'a \<Rightarrow>\<^sub>0 'b"} as an abstract
 | 
| 302 |   \emph{algebraic} type
 | |
| 70045 
7b6add80e3a5
fixed markup in Poly_Mapping; Free_Abelian_Groups (but not yet imported by Algebra!)
 paulson <lp15@cam.ac.uk> parents: 
70043diff
changeset | 303 |   providing operations like \emph{addition}, \emph{multiplication} without any notion
 | 
| 70043 | 304 | of key-order, data structures etc. This implementations-specific notions are | 
| 305 | easily introduced later for particular implementations but do not provide any | |
| 306 | gain for specifying logical properties of polynomials. | |
| 307 | \<close> | |
| 308 | ||
| 309 | subsection \<open>Additive structure\<close> | |
| 310 | ||
| 311 | text \<open> | |
| 312 | The additive structure covers the usual operations \<open>0\<close>, \<open>+\<close> and | |
| 313 | (unary and binary) \<open>-\<close>. Recalling the ultimate interpretation, it | |
| 314 | is obvious that these have just lift the corresponding operations on values | |
| 315 | to mappings. | |
| 316 | ||
| 317 | Isabelle has a rich hierarchy of algebraic type classes, and in such situations | |
| 318 | of pointwise lifting a typical pattern is to have instantiations for a considerable | |
| 319 | number of type classes. | |
| 320 | ||
| 321 | The operations themselves are specified using \<open>lift_definition\<close>, where | |
| 70045 
7b6add80e3a5
fixed markup in Poly_Mapping; Free_Abelian_Groups (but not yet imported by Algebra!)
 paulson <lp15@cam.ac.uk> parents: 
70043diff
changeset | 322 |   the proofs of the \emph{almost everywhere zero} property can be significantly involved.
 | 
| 70043 | 323 | |
| 324 |   The @{const lookup} operation is supposed to be usable explicitly (unless in
 | |
| 325 | other situations where the morphisms between types are somehow internal | |
| 326 |   to the \emph{lifting} package).  Hence it is good style to provide explicit rewrite
 | |
| 327 |   rules how @{const lookup} acts on operations immediately.
 | |
| 328 | \<close> | |
| 329 | ||
| 330 | instantiation poly_mapping :: (type, zero) zero | |
| 331 | begin | |
| 332 | ||
| 333 | lift_definition zero_poly_mapping :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 334 | is "\<lambda>k. 0" | |
| 335 | by simp | |
| 336 | ||
| 337 | instance .. | |
| 338 | ||
| 339 | end | |
| 340 | ||
| 341 | lemma Abs_poly_mapping [simp]: "Abs_poly_mapping (\<lambda>k. 0) = 0" | |
| 342 | by (simp add: zero_poly_mapping.abs_eq) | |
| 343 | ||
| 344 | lemma lookup_zero [simp]: "lookup 0 k = 0" | |
| 345 | by transfer rule | |
| 346 | ||
| 347 | instantiation poly_mapping :: (type, monoid_add) monoid_add | |
| 348 | begin | |
| 349 | ||
| 350 | lift_definition plus_poly_mapping :: | |
| 351 |     "('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> 'a \<Rightarrow>\<^sub>0 'b"
 | |
| 352 | is "\<lambda>f1 f2 k. f1 k + f2 k" | |
| 353 | proof - | |
| 354 | fix f1 f2 :: "'a \<Rightarrow> 'b" | |
| 355 |   assume "finite {k. f1 k \<noteq> 0}"
 | |
| 356 |     and "finite {k. f2 k \<noteq> 0}"
 | |
| 357 |   then have "finite ({k. f1 k \<noteq> 0} \<union> {k. f2 k \<noteq> 0})" by auto
 | |
| 358 |   moreover have "{x. f1 x + f2 x \<noteq> 0} \<subseteq> {k. f1 k \<noteq> 0} \<union> {k. f2 k \<noteq> 0}"
 | |
| 359 | by auto | |
| 360 |   ultimately show "finite {x. f1 x + f2 x \<noteq> 0}"
 | |
| 361 | by (blast intro: finite_subset) | |
| 362 | qed | |
| 363 | ||
| 364 | instance | |
| 365 | by intro_classes (transfer, simp add: fun_eq_iff ac_simps)+ | |
| 366 | ||
| 367 | end | |
| 368 | ||
| 369 | lemma lookup_add: | |
| 370 | "lookup (f + g) k = lookup f k + lookup g k" | |
| 371 | by transfer rule | |
| 372 | ||
| 373 | instance poly_mapping :: (type, comm_monoid_add) comm_monoid_add | |
| 374 | by intro_classes (transfer, simp add: fun_eq_iff ac_simps)+ | |
| 375 | ||
| 376 | lemma lookup_sum: "lookup (sum pp X) i = sum (\<lambda>x. lookup (pp x) i) X" | |
| 377 | by (induction rule: infinite_finite_induct) (auto simp: lookup_add) | |
| 378 | ||
| 379 | (*instance poly_mapping :: (type, "{monoid_add, cancel_semigroup_add}") cancel_semigroup_add
 | |
| 380 | by intro_classes (transfer, simp add: fun_eq_iff)+*) | |
| 381 | ||
| 382 | instantiation poly_mapping :: (type, cancel_comm_monoid_add) cancel_comm_monoid_add | |
| 383 | begin | |
| 384 | ||
| 385 | lift_definition minus_poly_mapping :: "('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> 'a \<Rightarrow>\<^sub>0 'b"
 | |
| 386 | is "\<lambda>f1 f2 k. f1 k - f2 k" | |
| 387 | proof - | |
| 388 | fix f1 f2 :: "'a \<Rightarrow> 'b" | |
| 389 |   assume "finite {k. f1 k \<noteq> 0}"
 | |
| 390 |     and "finite {k. f2 k \<noteq> 0}"
 | |
| 391 |   then have "finite ({k. f1 k \<noteq> 0} \<union> {k. f2 k \<noteq> 0})" by auto
 | |
| 392 |   moreover have "{x. f1 x - f2 x \<noteq> 0} \<subseteq> {k. f1 k \<noteq> 0} \<union> {k. f2 k \<noteq> 0}"
 | |
| 393 | by auto | |
| 394 |   ultimately show "finite {x. f1 x - f2 x \<noteq> 0}" by (blast intro: finite_subset)
 | |
| 395 | qed | |
| 396 | ||
| 397 | instance | |
| 398 | by intro_classes (transfer, simp add: fun_eq_iff diff_diff_add)+ | |
| 399 | ||
| 400 | end | |
| 401 | ||
| 402 | instantiation poly_mapping :: (type, ab_group_add) ab_group_add | |
| 403 | begin | |
| 404 | ||
| 405 | lift_definition uminus_poly_mapping :: "('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> 'a \<Rightarrow>\<^sub>0 'b"
 | |
| 406 | is uminus | |
| 407 | by simp | |
| 408 | ||
| 409 | ||
| 410 | instance | |
| 411 | by intro_classes (transfer, simp add: fun_eq_iff ac_simps)+ | |
| 412 | ||
| 413 | end | |
| 414 | ||
| 415 | lemma lookup_uminus [simp]: | |
| 416 | "lookup (- f) k = - lookup f k" | |
| 417 | by transfer simp | |
| 418 | ||
| 419 | lemma lookup_minus: | |
| 420 | "lookup (f - g) k = lookup f k - lookup g k" | |
| 421 | by transfer rule | |
| 422 | ||
| 423 | ||
| 424 | subsection \<open>Multiplicative structure\<close> | |
| 425 | ||
| 426 | instantiation poly_mapping :: (zero, zero_neq_one) zero_neq_one | |
| 427 | begin | |
| 428 | ||
| 429 | lift_definition one_poly_mapping :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 430 | is "\<lambda>k. 1 when k = 0" | |
| 431 | by simp | |
| 432 | ||
| 433 | instance | |
| 434 | by intro_classes (transfer, simp add: fun_eq_iff) | |
| 435 | ||
| 436 | end | |
| 437 | ||
| 438 | lemma lookup_one: | |
| 439 | "lookup 1 k = (1 when k = 0)" | |
| 440 | by transfer rule | |
| 441 | ||
| 442 | lemma lookup_one_zero [simp]: | |
| 443 | "lookup 1 0 = 1" | |
| 444 | by transfer simp | |
| 445 | ||
| 446 | definition prod_fun :: "('a \<Rightarrow> 'b) \<Rightarrow> ('a \<Rightarrow> 'b) \<Rightarrow> 'a::monoid_add \<Rightarrow> 'b::semiring_0"
 | |
| 447 | where | |
| 448 | "prod_fun f1 f2 k = (\<Sum>l. f1 l * (\<Sum>q. (f2 q when k = l + q)))" | |
| 449 | ||
| 450 | lemma prod_fun_unfold_prod: | |
| 451 | fixes f g :: "'a :: monoid_add \<Rightarrow> 'b::semiring_0" | |
| 452 |   assumes fin_f: "finite {a. f a \<noteq> 0}"
 | |
| 453 |   assumes fin_g: "finite {b. g b \<noteq> 0}"
 | |
| 454 | shows "prod_fun f g k = (\<Sum>(a, b). f a * g b when k = a + b)" | |
| 455 | proof - | |
| 456 |   let ?C = "{a. f a \<noteq> 0} \<times> {b. g b \<noteq> 0}"
 | |
| 457 | from fin_f fin_g have "finite ?C" by blast | |
| 458 |   moreover have "{a. \<exists>b. (f a * g b when k = a + b) \<noteq> 0} \<times>
 | |
| 459 |     {b. \<exists>a. (f a * g b when k = a + b) \<noteq> 0} \<subseteq> {a. f a \<noteq> 0} \<times> {b. g b \<noteq> 0}"
 | |
| 460 | by auto | |
| 461 | ultimately show ?thesis using fin_g | |
| 80095 | 462 | by (auto simp: prod_fun_def | 
| 70043 | 463 |       Sum_any.cartesian_product [of "{a. f a \<noteq> 0} \<times> {b. g b \<noteq> 0}"] Sum_any_right_distrib mult_when)
 | 
| 464 | qed | |
| 465 | ||
| 466 | lemma finite_prod_fun: | |
| 467 | fixes f1 f2 :: "'a :: monoid_add \<Rightarrow> 'b :: semiring_0" | |
| 468 |   assumes fin1: "finite {l. f1 l \<noteq> 0}"
 | |
| 469 |   and fin2: "finite {q. f2 q \<noteq> 0}"
 | |
| 470 |   shows "finite {k. prod_fun f1 f2 k \<noteq> 0}"
 | |
| 471 | proof - | |
| 472 |   have *: "finite {k. (\<exists>l. f1 l \<noteq> 0 \<and> (\<exists>q. f2 q \<noteq> 0 \<and> k = l + q))}"
 | |
| 473 | using assms by simp | |
| 474 |   { fix k l
 | |
| 475 |     have "{q. (f2 q when k = l + q) \<noteq> 0} \<subseteq> {q. f2 q \<noteq> 0 \<and> k = l + q}" by auto
 | |
| 476 |     with fin2 have "sum f2 {q. f2 q \<noteq> 0 \<and> k = l + q} = (\<Sum>q. (f2 q when k = l + q))"
 | |
| 477 |       by (simp add: Sum_any.expand_superset [of "{q. f2 q \<noteq> 0 \<and> k = l + q}"]) }
 | |
| 478 | note aux = this | |
| 479 |   have "{k. (\<Sum>l. f1 l * sum f2 {q. f2 q \<noteq> 0 \<and> k = l + q}) \<noteq> 0}
 | |
| 480 |     \<subseteq> {k. (\<exists>l. f1 l * sum f2 {q. f2 q \<noteq> 0 \<and> k = l + q} \<noteq> 0)}"
 | |
| 481 | by (auto elim!: Sum_any.not_neutral_obtains_not_neutral) | |
| 482 |   also have "\<dots> \<subseteq> {k. (\<exists>l. f1 l \<noteq> 0 \<and> sum f2 {q. f2 q \<noteq> 0 \<and> k = l + q} \<noteq> 0)}"
 | |
| 483 | by (auto dest: mult_not_zero) | |
| 484 |   also have "\<dots> \<subseteq> {k. (\<exists>l. f1 l \<noteq> 0 \<and> (\<exists>q. f2 q \<noteq> 0 \<and> k = l + q))}"
 | |
| 485 | by (auto elim!: sum.not_neutral_contains_not_neutral) | |
| 486 |   finally have "finite {k. (\<Sum>l. f1 l * sum f2 {q. f2 q \<noteq> 0 \<and> k = l + q}) \<noteq> 0}"
 | |
| 487 | using * by (rule finite_subset) | |
| 488 |   with aux have "finite {k. (\<Sum>l. f1 l * (\<Sum>q. (f2 q when k = l + q))) \<noteq> 0}"
 | |
| 489 | by simp | |
| 490 | with fin2 show ?thesis | |
| 491 | by (simp add: prod_fun_def) | |
| 492 | qed | |
| 493 | ||
| 494 | instantiation poly_mapping :: (monoid_add, semiring_0) semiring_0 | |
| 495 | begin | |
| 496 | ||
| 497 | lift_definition times_poly_mapping :: "('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> 'a \<Rightarrow>\<^sub>0 'b"
 | |
| 498 | is prod_fun | |
| 499 | by(rule finite_prod_fun) | |
| 500 | ||
| 501 | instance | |
| 502 | proof | |
| 503 | fix a b c :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 504 | show "a * b * c = a * (b * c)" | |
| 505 | proof transfer | |
| 506 | fix f g h :: "'a \<Rightarrow> 'b" | |
| 507 |     assume fin_f: "finite {a. f a \<noteq> 0}" (is "finite ?F")
 | |
| 508 |     assume fin_g: "finite {b. g b \<noteq> 0}" (is "finite ?G")
 | |
| 509 |     assume fin_h: "finite {c. h c \<noteq> 0}" (is "finite ?H")
 | |
| 510 |     from fin_f fin_g have fin_fg: "finite {(a, b). f a * g b \<noteq> 0}" (is "finite ?FG")
 | |
| 511 | by (rule finite_mult_not_eq_zero_prodI) | |
| 512 |     from fin_g fin_h have fin_gh: "finite {(b, c). g b * h c \<noteq> 0}" (is "finite ?GH")
 | |
| 513 | by (rule finite_mult_not_eq_zero_prodI) | |
| 514 |     from fin_f fin_g have fin_fg': "finite {a + b | a b. f a * g b \<noteq> 0}" (is "finite ?FG'")
 | |
| 515 | by (rule finite_mult_not_eq_zero_sumI) | |
| 516 |     then have fin_fg'': "finite {d. (\<Sum>(a, b). f a * g b when d = a + b) \<noteq> 0}"
 | |
| 517 | by (auto intro: finite_Sum_any_not_eq_zero_weakenI) | |
| 518 |     from fin_g fin_h have fin_gh': "finite {b + c | b c. g b * h c \<noteq> 0}" (is "finite ?GH'")
 | |
| 519 | by (rule finite_mult_not_eq_zero_sumI) | |
| 520 |     then have fin_gh'': "finite {d. (\<Sum>(b, c). g b * h c when d = b + c) \<noteq> 0}"
 | |
| 521 | by (auto intro: finite_Sum_any_not_eq_zero_weakenI) | |
| 522 | show "prod_fun (prod_fun f g) h = prod_fun f (prod_fun g h)" (is "?lhs = ?rhs") | |
| 523 | proof | |
| 524 | fix k | |
| 525 | from fin_f fin_g fin_h fin_fg'' | |
| 526 | have "?lhs k = (\<Sum>(ab, c). (\<Sum>(a, b). f a * g b when ab = a + b) * h c when k = ab + c)" | |
| 527 | by (simp add: prod_fun_unfold_prod) | |
| 528 | also have "\<dots> = (\<Sum>(ab, c). (\<Sum>(a, b). f a * g b * h c when k = ab + c when ab = a + b))" | |
| 80095 | 529 | using fin_fg | 
| 530 | apply (simp add: Sum_any_left_distrib split_def flip: Sum_any_when_independent) | |
| 531 | apply (simp add: when_when when_mult mult_when conj_commute) | |
| 70043 | 532 | done | 
| 533 | also have "\<dots> = (\<Sum>(ab, c, a, b). f a * g b * h c when k = ab + c when ab = a + b)" | |
| 534 | apply (subst Sum_any.cartesian_product2 [of "(?FG' \<times> ?H) \<times> ?FG"]) | |
| 80095 | 535 | apply (auto simp: finite_cartesian_product_iff fin_fg fin_fg' fin_h dest: mult_not_zero) | 
| 70043 | 536 | done | 
| 537 | also have "\<dots> = (\<Sum>(ab, c, a, b). f a * g b * h c when k = a + b + c when ab = a + b)" | |
| 538 | by (rule Sum_any.cong) (simp add: split_def when_def) | |
| 539 | also have "\<dots> = (\<Sum>(ab, cab). (case cab of (c, a, b) \<Rightarrow> f a * g b * h c when k = a + b + c) | |
| 540 | when ab = (case cab of (c, a, b) \<Rightarrow> a + b))" | |
| 541 | by (simp add: split_def) | |
| 542 | also have "\<dots> = (\<Sum>(c, a, b). f a * g b * h c when k = a + b + c)" | |
| 543 | by (simp add: Sum_any_when_dependent_prod_left) | |
| 544 | also have "\<dots> = (\<Sum>(bc, cab). (case cab of (c, a, b) \<Rightarrow> f a * g b * h c when k = a + b + c) | |
| 545 | when bc = (case cab of (c, a, b) \<Rightarrow> b + c))" | |
| 546 | by (simp add: Sum_any_when_dependent_prod_left) | |
| 547 | also have "\<dots> = (\<Sum>(bc, c, a, b). f a * g b * h c when k = a + b + c when bc = b + c)" | |
| 548 | by (simp add: split_def) | |
| 549 | also have "\<dots> = (\<Sum>(bc, c, a, b). f a * g b * h c when bc = b + c when k = a + bc)" | |
| 550 | by (rule Sum_any.cong) (simp add: split_def when_def ac_simps) | |
| 551 | also have "\<dots> = (\<Sum>(a, bc, b, c). f a * g b * h c when bc = b + c when k = a + bc)" | |
| 552 | proof - | |
| 553 | have "bij (\<lambda>(a, d, b, c). (d, c, a, b))" | |
| 554 | by (auto intro!: bijI injI surjI [of _ "\<lambda>(d, c, a, b). (a, d, b, c)"] simp add: split_def) | |
| 555 | then show ?thesis | |
| 556 | by (rule Sum_any.reindex_cong) auto | |
| 557 | qed | |
| 558 | also have "\<dots> = (\<Sum>(a, bc). (\<Sum>(b, c). f a * g b * h c when bc = b + c when k = a + bc))" | |
| 559 | apply (subst Sum_any.cartesian_product2 [of "(?F \<times> ?GH') \<times> ?GH"]) | |
| 80095 | 560 | apply (auto simp: finite_cartesian_product_iff fin_f fin_gh fin_gh' ac_simps dest: mult_not_zero) | 
| 70043 | 561 | done | 
| 562 | also have "\<dots> = (\<Sum>(a, bc). f a * (\<Sum>(b, c). g b * h c when bc = b + c) when k = a + bc)" | |
| 563 | apply (subst Sum_any_right_distrib) | |
| 564 | using fin_gh apply (simp add: split_def) | |
| 565 | apply (subst Sum_any_when_independent [symmetric]) | |
| 566 | apply (simp add: when_when when_mult mult_when split_def ac_simps) | |
| 567 | done | |
| 568 | also from fin_f fin_g fin_h fin_gh'' | |
| 569 | have "\<dots> = ?rhs k" | |
| 570 | by (simp add: prod_fun_unfold_prod) | |
| 571 | finally show "?lhs k = ?rhs k" . | |
| 572 | qed | |
| 573 | qed | |
| 574 | show "(a + b) * c = a * c + b * c" | |
| 575 | proof transfer | |
| 576 | fix f g h :: "'a \<Rightarrow> 'b" | |
| 577 |     assume fin_f: "finite {k. f k \<noteq> 0}"
 | |
| 578 |     assume fin_g: "finite {k. g k \<noteq> 0}"
 | |
| 579 |     assume fin_h: "finite {k. h k \<noteq> 0}"
 | |
| 580 | show "prod_fun (\<lambda>k. f k + g k) h = (\<lambda>k. prod_fun f h k + prod_fun g h k)" | |
| 581 | apply (rule ext) | |
| 80095 | 582 | apply (simp add: prod_fun_def algebra_simps) | 
| 583 | by (simp add: Sum_any.distrib fin_f fin_g finite_mult_not_eq_zero_rightI) | |
| 70043 | 584 | qed | 
| 585 | show "a * (b + c) = a * b + a * c" | |
| 586 | proof transfer | |
| 587 | fix f g h :: "'a \<Rightarrow> 'b" | |
| 588 |     assume fin_f: "finite {k. f k \<noteq> 0}"
 | |
| 589 |     assume fin_g: "finite {k. g k \<noteq> 0}"
 | |
| 590 |     assume fin_h: "finite {k. h k \<noteq> 0}"
 | |
| 591 | show "prod_fun f (\<lambda>k. g k + h k) = (\<lambda>k. prod_fun f g k + prod_fun f h k)" | |
| 592 | apply (rule ext) | |
| 80095 | 593 | apply (auto simp: prod_fun_def Sum_any.distrib algebra_simps when_add_distrib fin_g fin_h) | 
| 594 | by (simp add: Sum_any.distrib fin_f finite_mult_not_eq_zero_rightI) | |
| 70043 | 595 | qed | 
| 596 | show "0 * a = 0" | |
| 597 | by transfer (simp add: prod_fun_def [abs_def]) | |
| 598 | show "a * 0 = 0" | |
| 599 | by transfer (simp add: prod_fun_def [abs_def]) | |
| 600 | qed | |
| 601 | ||
| 602 | end | |
| 603 | ||
| 604 | lemma lookup_mult: | |
| 605 | "lookup (f * g) k = (\<Sum>l. lookup f l * (\<Sum>q. lookup g q when k = l + q))" | |
| 606 | by transfer (simp add: prod_fun_def) | |
| 607 | ||
| 608 | instance poly_mapping :: (comm_monoid_add, comm_semiring_0) comm_semiring_0 | |
| 609 | proof | |
| 610 | fix a b c :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 611 | show "a * b = b * a" | |
| 612 | proof transfer | |
| 613 | fix f g :: "'a \<Rightarrow> 'b" | |
| 614 |     assume fin_f: "finite {a. f a \<noteq> 0}"
 | |
| 615 |     assume fin_g: "finite {b. g b \<noteq> 0}"
 | |
| 616 | show "prod_fun f g = prod_fun g f" | |
| 617 | proof | |
| 618 | fix k | |
| 619 |       have fin1: "\<And>l. finite {a. (f a when k = l + a) \<noteq> 0}"
 | |
| 620 | using fin_f by auto | |
| 621 |       have fin2: "\<And>l. finite {b. (g b when k = l + b) \<noteq> 0}"
 | |
| 622 | using fin_g by auto | |
| 623 |       from fin_f fin_g have "finite {(a, b). f a \<noteq> 0 \<and> g b \<noteq> 0}" (is "finite ?AB")
 | |
| 624 | by simp | |
| 80095 | 625 | have "(\<Sum>a. \<Sum>n. f a * (g n when k = a + n)) = (\<Sum>a. \<Sum>n. g a * (f n when k = a + n))" | 
| 626 | by (subst Sum_any.swap [OF \<open>finite ?AB\<close>]) (auto simp: mult_when ac_simps) | |
| 627 | then show "prod_fun f g k = prod_fun g f k" | |
| 628 | by (simp add: prod_fun_def Sum_any_right_distrib [OF fin2] Sum_any_right_distrib [OF fin1]) | |
| 70043 | 629 | qed | 
| 630 | qed | |
| 631 | show "(a + b) * c = a * c + b * c" | |
| 632 | proof transfer | |
| 633 | fix f g h :: "'a \<Rightarrow> 'b" | |
| 634 |     assume fin_f: "finite {k. f k \<noteq> 0}"
 | |
| 635 |     assume fin_g: "finite {k. g k \<noteq> 0}"
 | |
| 636 |     assume fin_h: "finite {k. h k \<noteq> 0}"
 | |
| 637 | show "prod_fun (\<lambda>k. f k + g k) h = (\<lambda>k. prod_fun f h k + prod_fun g h k)" | |
| 80095 | 638 | by (auto simp: prod_fun_def fun_eq_iff algebra_simps | 
| 639 | Sum_any.distrib fin_f fin_g finite_mult_not_eq_zero_rightI) | |
| 70043 | 640 | qed | 
| 641 | qed | |
| 642 | ||
| 643 | instance poly_mapping :: (monoid_add, semiring_0_cancel) semiring_0_cancel | |
| 644 | .. | |
| 645 | ||
| 646 | instance poly_mapping :: (comm_monoid_add, comm_semiring_0_cancel) comm_semiring_0_cancel | |
| 647 | .. | |
| 648 | ||
| 649 | instance poly_mapping :: (monoid_add, semiring_1) semiring_1 | |
| 650 | proof | |
| 651 | fix a :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 652 | show "1 * a = a" | |
| 653 | by transfer (simp add: prod_fun_def [abs_def] when_mult) | |
| 654 | show "a * 1 = a" | |
| 655 | apply transfer | |
| 656 | apply (simp add: prod_fun_def [abs_def] Sum_any_right_distrib Sum_any_left_distrib mult_when) | |
| 657 | apply (subst when_commute) | |
| 658 | apply simp | |
| 659 | done | |
| 660 | qed | |
| 661 | ||
| 662 | instance poly_mapping :: (comm_monoid_add, comm_semiring_1) comm_semiring_1 | |
| 663 | proof | |
| 664 | fix a :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 665 | show "1 * a = a" | |
| 666 | by transfer (simp add: prod_fun_def [abs_def]) | |
| 667 | qed | |
| 668 | ||
| 669 | instance poly_mapping :: (monoid_add, semiring_1_cancel) semiring_1_cancel | |
| 670 | .. | |
| 671 | ||
| 672 | instance poly_mapping :: (monoid_add, ring) ring | |
| 673 | .. | |
| 674 | ||
| 675 | instance poly_mapping :: (comm_monoid_add, comm_ring) comm_ring | |
| 676 | .. | |
| 677 | ||
| 678 | instance poly_mapping :: (monoid_add, ring_1) ring_1 | |
| 679 | .. | |
| 680 | ||
| 681 | instance poly_mapping :: (comm_monoid_add, comm_ring_1) comm_ring_1 | |
| 682 | .. | |
| 683 | ||
| 684 | ||
| 685 | subsection \<open>Single-point mappings\<close> | |
| 686 | ||
| 687 | lift_definition single :: "'a \<Rightarrow> 'b \<Rightarrow> 'a \<Rightarrow>\<^sub>0 'b::zero" | |
| 688 | is "\<lambda>k v k'. (v when k = k')" | |
| 689 | by simp | |
| 690 | ||
| 691 | lemma inj_single [iff]: | |
| 692 | "inj (single k)" | |
| 693 | proof (rule injI, transfer) | |
| 694 | fix k :: 'b and a b :: "'a::zero" | |
| 695 | assume "(\<lambda>k'. a when k = k') = (\<lambda>k'. b when k = k')" | |
| 696 | then have "(\<lambda>k'. a when k = k') k = (\<lambda>k'. b when k = k') k" | |
| 697 | by (rule arg_cong) | |
| 698 | then show "a = b" by simp | |
| 699 | qed | |
| 700 | ||
| 701 | lemma lookup_single: | |
| 702 | "lookup (single k v) k' = (v when k = k')" | |
| 80095 | 703 | by (simp add: single.rep_eq) | 
| 70043 | 704 | |
| 705 | lemma lookup_single_eq [simp]: | |
| 706 | "lookup (single k v) k = v" | |
| 707 | by transfer simp | |
| 708 | ||
| 709 | lemma lookup_single_not_eq: | |
| 710 | "k \<noteq> k' \<Longrightarrow> lookup (single k v) k' = 0" | |
| 711 | by transfer simp | |
| 712 | ||
| 713 | lemma single_zero [simp]: | |
| 714 | "single k 0 = 0" | |
| 715 | by transfer simp | |
| 716 | ||
| 717 | lemma single_one [simp]: | |
| 718 | "single 0 1 = 1" | |
| 719 | by transfer simp | |
| 720 | ||
| 721 | lemma single_add: | |
| 722 | "single k (a + b) = single k a + single k b" | |
| 723 | by transfer (simp add: fun_eq_iff when_add_distrib) | |
| 724 | ||
| 725 | lemma single_uminus: | |
| 726 | "single k (- a) = - single k a" | |
| 727 | by transfer (simp add: fun_eq_iff when_uminus_distrib) | |
| 728 | ||
| 729 | lemma single_diff: | |
| 730 | "single k (a - b) = single k a - single k b" | |
| 731 | by transfer (simp add: fun_eq_iff when_diff_distrib) | |
| 732 | ||
| 733 | lemma single_numeral [simp]: | |
| 734 | "single 0 (numeral n) = numeral n" | |
| 735 | by (induct n) (simp_all only: numeral.simps numeral_add single_zero single_one single_add) | |
| 736 | ||
| 737 | lemma lookup_numeral: | |
| 738 | "lookup (numeral n) k = (numeral n when k = 0)" | |
| 739 | proof - | |
| 740 | have "lookup (numeral n) k = lookup (single 0 (numeral n)) k" | |
| 741 | by simp | |
| 742 | then show ?thesis unfolding lookup_single by simp | |
| 743 | qed | |
| 744 | ||
| 745 | lemma single_of_nat [simp]: | |
| 746 | "single 0 (of_nat n) = of_nat n" | |
| 747 | by (induct n) (simp_all add: single_add) | |
| 748 | ||
| 749 | lemma lookup_of_nat: | |
| 750 | "lookup (of_nat n) k = (of_nat n when k = 0)" | |
| 751 | proof - | |
| 752 | have "lookup (of_nat n) k = lookup (single 0 (of_nat n)) k" | |
| 753 | by simp | |
| 754 | then show ?thesis unfolding lookup_single by simp | |
| 755 | qed | |
| 756 | ||
| 757 | lemma of_nat_single: | |
| 758 | "of_nat = single 0 \<circ> of_nat" | |
| 759 | by (simp add: fun_eq_iff) | |
| 760 | ||
| 761 | lemma mult_single: | |
| 762 | "single k a * single l b = single (k + l) (a * b)" | |
| 763 | proof transfer | |
| 764 | fix k l :: 'a and a b :: 'b | |
| 765 | show "prod_fun (\<lambda>k'. a when k = k') (\<lambda>k'. b when l = k') = (\<lambda>k'. a * b when k + l = k')" | |
| 766 | proof | |
| 767 | fix k' | |
| 768 | have "prod_fun (\<lambda>k'. a when k = k') (\<lambda>k'. b when l = k') k' = (\<Sum>n. a * b when l = n when k' = k + n)" | |
| 769 | by (simp add: prod_fun_def Sum_any_right_distrib mult_when when_mult) | |
| 770 | also have "\<dots> = (\<Sum>n. a * b when k' = k + n when l = n)" | |
| 771 | by (simp add: when_when conj_commute) | |
| 772 | also have "\<dots> = (a * b when k' = k + l)" | |
| 773 | by simp | |
| 774 | also have "\<dots> = (a * b when k + l = k')" | |
| 775 | by (simp add: when_def) | |
| 776 | finally show "prod_fun (\<lambda>k'. a when k = k') (\<lambda>k'. b when l = k') k' = | |
| 777 | (\<lambda>k'. a * b when k + l = k') k'" . | |
| 778 | qed | |
| 779 | qed | |
| 780 | ||
| 781 | instance poly_mapping :: (monoid_add, semiring_char_0) semiring_char_0 | |
| 782 | by intro_classes (auto intro: inj_compose inj_of_nat simp add: of_nat_single) | |
| 783 | ||
| 784 | instance poly_mapping :: (monoid_add, ring_char_0) ring_char_0 | |
| 785 | .. | |
| 786 | ||
| 787 | lemma single_of_int [simp]: | |
| 788 | "single 0 (of_int k) = of_int k" | |
| 789 | by (cases k) (simp_all add: single_diff single_uminus) | |
| 790 | ||
| 791 | lemma lookup_of_int: | |
| 792 | "lookup (of_int l) k = (of_int l when k = 0)" | |
| 80095 | 793 | by (metis lookup_single_not_eq single.rep_eq single_of_int) | 
| 70043 | 794 | |
| 795 | ||
| 796 | subsection \<open>Integral domains\<close> | |
| 797 | ||
| 798 | instance poly_mapping :: ("{ordered_cancel_comm_monoid_add, linorder}", semiring_no_zero_divisors) semiring_no_zero_divisors
 | |
| 799 |   text \<open>The @{class "linorder"} constraint is a pragmatic device for the proof --- maybe it can be dropped\<close>
 | |
| 800 | proof | |
| 801 | fix f g :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 802 | assume "f \<noteq> 0" and "g \<noteq> 0" | |
| 803 | then show "f * g \<noteq> 0" | |
| 804 | proof transfer | |
| 805 | fix f g :: "'a \<Rightarrow> 'b" | |
| 806 |     define F where "F = {a. f a \<noteq> 0}"
 | |
| 807 |     moreover define G where "G = {a. g a \<noteq> 0}"
 | |
| 808 | ultimately have [simp]: | |
| 809 | "\<And>a. f a \<noteq> 0 \<longleftrightarrow> a \<in> F" | |
| 810 | "\<And>b. g b \<noteq> 0 \<longleftrightarrow> b \<in> G" | |
| 811 | by simp_all | |
| 812 |     assume "finite {a. f a \<noteq> 0}"
 | |
| 813 | then have [simp]: "finite F" | |
| 814 | by simp | |
| 815 |     assume "finite {a. g a \<noteq> 0}"
 | |
| 816 | then have [simp]: "finite G" | |
| 817 | by simp | |
| 818 | assume "f \<noteq> (\<lambda>a. 0)" | |
| 819 | then obtain a where "f a \<noteq> 0" | |
| 80095 | 820 | by (auto simp: fun_eq_iff) | 
| 70043 | 821 | assume "g \<noteq> (\<lambda>b. 0)" | 
| 822 | then obtain b where "g b \<noteq> 0" | |
| 80095 | 823 | by (auto simp: fun_eq_iff) | 
| 70043 | 824 |     from \<open>f a \<noteq> 0\<close> and \<open>g b \<noteq> 0\<close> have "F \<noteq> {}" and "G \<noteq> {}"
 | 
| 825 | by auto | |
| 826 |     note Max_F = \<open>finite F\<close> \<open>F \<noteq> {}\<close>
 | |
| 827 |     note Max_G = \<open>finite G\<close> \<open>G \<noteq> {}\<close>
 | |
| 828 | from Max_F and Max_G have [simp]: | |
| 829 | "Max F \<in> F" | |
| 830 | "Max G \<in> G" | |
| 831 | by auto | |
| 832 | from Max_F Max_G have [dest!]: | |
| 833 | "\<And>a. a \<in> F \<Longrightarrow> a \<le> Max F" | |
| 834 | "\<And>b. b \<in> G \<Longrightarrow> b \<le> Max G" | |
| 835 | by auto | |
| 836 | define q where "q = Max F + Max G" | |
| 837 | have "(\<Sum>(a, b). f a * g b when q = a + b) = | |
| 838 | (\<Sum>(a, b). f a * g b when q = a + b when a \<in> F \<and> b \<in> G)" | |
| 80095 | 839 | by (rule Sum_any.cong) (auto simp: split_def when_def q_def intro: ccontr) | 
| 70043 | 840 | also have "\<dots> = | 
| 841 | (\<Sum>(a, b). f a * g b when (Max F, Max G) = (a, b))" | |
| 842 | proof (rule Sum_any.cong) | |
| 843 | fix ab :: "'a \<times> 'a" | |
| 844 | obtain a b where [simp]: "ab = (a, b)" | |
| 845 | by (cases ab) simp_all | |
| 846 | have [dest!]: | |
| 847 | "a \<le> Max F \<Longrightarrow> Max F \<noteq> a \<Longrightarrow> a < Max F" | |
| 848 | "b \<le> Max G \<Longrightarrow> Max G \<noteq> b \<Longrightarrow> b < Max G" | |
| 849 | by auto | |
| 850 | show "(case ab of (a, b) \<Rightarrow> f a * g b when q = a + b when a \<in> F \<and> b \<in> G) = | |
| 851 | (case ab of (a, b) \<Rightarrow> f a * g b when (Max F, Max G) = (a, b))" | |
| 80095 | 852 | by (auto simp: split_def when_def q_def dest: add_strict_mono [of a "Max F" b "Max G"]) | 
| 70043 | 853 | qed | 
| 854 | also have "\<dots> = (\<Sum>ab. (case ab of (a, b) \<Rightarrow> f a * g b) when | |
| 855 | (Max F, Max G) = ab)" | |
| 856 | unfolding split_def when_def by auto | |
| 857 | also have "\<dots> \<noteq> 0" | |
| 858 | by simp | |
| 859 | finally have "prod_fun f g q \<noteq> 0" | |
| 860 | by (simp add: prod_fun_unfold_prod) | |
| 861 | then show "prod_fun f g \<noteq> (\<lambda>k. 0)" | |
| 80095 | 862 | by (auto simp: fun_eq_iff) | 
| 70043 | 863 | qed | 
| 864 | qed | |
| 865 | ||
| 866 | instance poly_mapping :: ("{ordered_cancel_comm_monoid_add, linorder}", ring_no_zero_divisors) ring_no_zero_divisors
 | |
| 867 | .. | |
| 868 | ||
| 869 | instance poly_mapping :: ("{ordered_cancel_comm_monoid_add, linorder}", ring_1_no_zero_divisors) ring_1_no_zero_divisors
 | |
| 870 | .. | |
| 871 | ||
| 872 | instance poly_mapping :: ("{ordered_cancel_comm_monoid_add, linorder}", idom) idom
 | |
| 873 | .. | |
| 874 | ||
| 875 | ||
| 876 | subsection \<open>Mapping order\<close> | |
| 877 | ||
| 878 | instantiation poly_mapping :: (linorder, "{zero, linorder}") linorder
 | |
| 879 | begin | |
| 880 | ||
| 881 | lift_definition less_poly_mapping :: "('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> bool"
 | |
| 882 | is less_fun | |
| 883 | . | |
| 884 | ||
| 885 | lift_definition less_eq_poly_mapping :: "('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> bool"
 | |
| 886 | is "\<lambda>f g. less_fun f g \<or> f = g" | |
| 887 | . | |
| 888 | ||
| 77955 
c4677a6aae2c
more standard name bindings (amending 5bf71b4da706): avoid odd full_name like "Orderings.class.Orderings.preorder.of_class.intro" with many redundant name space accesses;
 wenzelm parents: 
76987diff
changeset | 889 | instance proof (rule linorder.intro_of_class) | 
| 70043 | 890 | show "class.linorder (less_eq :: (_ \<Rightarrow>\<^sub>0 _) \<Rightarrow> _) less" | 
| 891 | proof (rule linorder_strictI, rule order_strictI) | |
| 892 | fix f g h :: "'a \<Rightarrow>\<^sub>0 'b" | |
| 893 | show "f \<le> g \<longleftrightarrow> f < g \<or> f = g" | |
| 894 | by transfer (rule refl) | |
| 895 | show "\<not> f < f" | |
| 896 | by transfer (rule less_fun_irrefl) | |
| 897 | show "f < g \<or> f = g \<or> g < f" | |
| 898 | proof transfer | |
| 899 | fix f g :: "'a \<Rightarrow> 'b" | |
| 900 |       assume "finite {k. f k \<noteq> 0}" and "finite {k. g k \<noteq> 0}"
 | |
| 901 |       then have "finite ({k. f k \<noteq> 0} \<union> {k. g k \<noteq> 0})"
 | |
| 902 | by simp | |
| 903 |       moreover have "{k. f k \<noteq> g k} \<subseteq> {k. f k \<noteq> 0} \<union> {k. g k \<noteq> 0}"
 | |
| 904 | by auto | |
| 905 |       ultimately have "finite {k. f k \<noteq> g k}"
 | |
| 906 | by (rule rev_finite_subset) | |
| 907 | then show "less_fun f g \<or> f = g \<or> less_fun g f" | |
| 908 | by (rule less_fun_trichotomy) | |
| 909 | qed | |
| 910 | assume "f < g" then show "\<not> g < f" | |
| 911 | by transfer (rule less_fun_asym) | |
| 912 | note \<open>f < g\<close> moreover assume "g < h" | |
| 913 | ultimately show "f < h" | |
| 914 | by transfer (rule less_fun_trans) | |
| 915 | qed | |
| 916 | qed | |
| 917 | ||
| 918 | end | |
| 919 | ||
| 920 | instance poly_mapping :: (linorder, "{ordered_comm_monoid_add, ordered_ab_semigroup_add_imp_le, linorder}") ordered_ab_semigroup_add
 | |
| 921 | proof (intro_classes, transfer) | |
| 922 | fix f g h :: "'a \<Rightarrow> 'b" | |
| 923 | assume *: "less_fun f g \<or> f = g" | |
| 924 |   { assume "less_fun f g"
 | |
| 925 | then obtain k where "f k < g k" "(\<And>k'. k' < k \<Longrightarrow> f k' = g k')" | |
| 926 | by (blast elim!: less_funE) | |
| 927 | then have "h k + f k < h k + g k" "(\<And>k'. k' < k \<Longrightarrow> h k' + f k' = h k' + g k')" | |
| 928 | by simp_all | |
| 929 | then have "less_fun (\<lambda>k. h k + f k) (\<lambda>k. h k + g k)" | |
| 930 | by (blast intro: less_funI) | |
| 931 | } | |
| 932 | with * show "less_fun (\<lambda>k. h k + f k) (\<lambda>k. h k + g k) \<or> (\<lambda>k. h k + f k) = (\<lambda>k. h k + g k)" | |
| 80095 | 933 | by (auto simp: fun_eq_iff) | 
| 70043 | 934 | qed | 
| 935 | ||
| 936 | instance poly_mapping :: (linorder, "{ordered_comm_monoid_add, ordered_ab_semigroup_add_imp_le, cancel_comm_monoid_add, linorder}") linordered_cancel_ab_semigroup_add
 | |
| 937 | .. | |
| 938 | ||
| 939 | instance poly_mapping :: (linorder, "{ordered_comm_monoid_add, ordered_ab_semigroup_add_imp_le, cancel_comm_monoid_add, linorder}") ordered_comm_monoid_add
 | |
| 940 | .. | |
| 941 | ||
| 942 | instance poly_mapping :: (linorder, "{ordered_comm_monoid_add, ordered_ab_semigroup_add_imp_le, cancel_comm_monoid_add, linorder}") ordered_cancel_comm_monoid_add
 | |
| 943 | .. | |
| 944 | ||
| 945 | instance poly_mapping :: (linorder, linordered_ab_group_add) linordered_ab_group_add | |
| 946 | .. | |
| 947 | ||
| 948 | text \<open> | |
| 949 | For pragmatism we leave out the final elements in the hierarchy: | |
| 950 |   @{class linordered_ring}, @{class linordered_ring_strict}, @{class linordered_idom};
 | |
| 951 | remember that the order instance is a mere technical device, not a deeper algebraic | |
| 952 | property. | |
| 953 | \<close> | |
| 954 | ||
| 955 | ||
| 956 | subsection \<open>Fundamental mapping notions\<close> | |
| 957 | ||
| 958 | lift_definition keys :: "('a \<Rightarrow>\<^sub>0 'b::zero) \<Rightarrow> 'a set"
 | |
| 959 |   is "\<lambda>f. {k. f k \<noteq> 0}" .
 | |
| 960 | ||
| 961 | lift_definition range :: "('a \<Rightarrow>\<^sub>0 'b::zero) \<Rightarrow> 'b set"
 | |
| 962 |   is "\<lambda>f :: 'a \<Rightarrow> 'b. Set.range f - {0}" .
 | |
| 963 | ||
| 964 | lemma finite_keys [simp]: | |
| 965 | "finite (keys f)" | |
| 966 | by transfer | |
| 967 | ||
| 968 | lemma not_in_keys_iff_lookup_eq_zero: | |
| 969 | "k \<notin> keys f \<longleftrightarrow> lookup f k = 0" | |
| 970 | by transfer simp | |
| 971 | ||
| 972 | lemma lookup_not_eq_zero_eq_in_keys: | |
| 973 | "lookup f k \<noteq> 0 \<longleftrightarrow> k \<in> keys f" | |
| 974 | by transfer simp | |
| 975 | ||
| 976 | lemma lookup_eq_zero_in_keys_contradict [dest]: | |
| 977 | "lookup f k = 0 \<Longrightarrow> \<not> k \<in> keys f" | |
| 978 | by (simp add: not_in_keys_iff_lookup_eq_zero) | |
| 979 | ||
| 980 | lemma finite_range [simp]: "finite (Poly_Mapping.range p)" | |
| 981 | proof transfer | |
| 982 | fix f :: "'b \<Rightarrow> 'a" | |
| 983 |   assume *: "finite {x. f x \<noteq> 0}"
 | |
| 984 |   have "Set.range f - {0} \<subseteq> f ` {x. f x \<noteq> 0}"
 | |
| 985 | by auto | |
| 986 |   thus "finite (Set.range f - {0})"
 | |
| 987 | by(rule finite_subset)(rule finite_imageI[OF *]) | |
| 988 | qed | |
| 989 | ||
| 990 | lemma in_keys_lookup_in_range [simp]: | |
| 991 | "k \<in> keys f \<Longrightarrow> lookup f k \<in> range f" | |
| 992 | by transfer simp | |
| 993 | ||
| 994 | lemma in_keys_iff: "x \<in> (keys s) = (lookup s x \<noteq> 0)" | |
| 995 | by (transfer, simp) | |
| 996 | ||
| 997 | lemma keys_zero [simp]: | |
| 998 |   "keys 0 = {}"
 | |
| 999 | by transfer simp | |
| 1000 | ||
| 1001 | lemma range_zero [simp]: | |
| 1002 |   "range 0 = {}"
 | |
| 1003 | by transfer auto | |
| 1004 | ||
| 1005 | lemma keys_add: | |
| 1006 | "keys (f + g) \<subseteq> keys f \<union> keys g" | |
| 1007 | by transfer auto | |
| 1008 | ||
| 1009 | lemma keys_one [simp]: | |
| 1010 |   "keys 1 = {0}"
 | |
| 1011 | by transfer simp | |
| 1012 | ||
| 1013 | lemma range_one [simp]: | |
| 1014 |   "range 1 = {1}"
 | |
| 80095 | 1015 | by transfer (auto simp: when_def) | 
| 70043 | 1016 | |
| 1017 | lemma keys_single [simp]: | |
| 1018 |   "keys (single k v) = (if v = 0 then {} else {k})"
 | |
| 1019 | by transfer simp | |
| 1020 | ||
| 1021 | lemma range_single [simp]: | |
| 1022 |   "range (single k v) = (if v = 0 then {} else {v})"
 | |
| 80095 | 1023 | by transfer (auto simp: when_def) | 
| 70043 | 1024 | |
| 1025 | lemma keys_mult: | |
| 1026 |   "keys (f * g) \<subseteq> {a + b | a b. a \<in> keys f \<and> b \<in> keys g}"
 | |
| 1027 | apply transfer | |
| 80095 | 1028 | apply (force simp: prod_fun_def dest!: mult_not_zero elim!: Sum_any.not_neutral_obtains_not_neutral) | 
| 70043 | 1029 | done | 
| 1030 | ||
| 1031 | lemma setsum_keys_plus_distrib: | |
| 1032 | assumes hom_0: "\<And>k. f k 0 = 0" | |
| 1033 | and hom_plus: "\<And>k. k \<in> Poly_Mapping.keys p \<union> Poly_Mapping.keys q \<Longrightarrow> f k (Poly_Mapping.lookup p k + Poly_Mapping.lookup q k) = f k (Poly_Mapping.lookup p k) + f k (Poly_Mapping.lookup q k)" | |
| 1034 | shows | |
| 1035 | "(\<Sum>k\<in>Poly_Mapping.keys (p + q). f k (Poly_Mapping.lookup (p + q) k)) = | |
| 1036 | (\<Sum>k\<in>Poly_Mapping.keys p. f k (Poly_Mapping.lookup p k)) + | |
| 1037 | (\<Sum>k\<in>Poly_Mapping.keys q. f k (Poly_Mapping.lookup q k))" | |
| 1038 | (is "?lhs = ?p + ?q") | |
| 1039 | proof - | |
| 1040 | let ?A = "Poly_Mapping.keys p \<union> Poly_Mapping.keys q" | |
| 1041 | have "?lhs = (\<Sum>k\<in>?A. f k (Poly_Mapping.lookup p k + Poly_Mapping.lookup q k))" | |
| 80095 | 1042 | by(intro sum.mono_neutral_cong_left) (auto simp: sum.mono_neutral_cong_left hom_0 in_keys_iff lookup_add) | 
| 70043 | 1043 | also have "\<dots> = (\<Sum>k\<in>?A. f k (Poly_Mapping.lookup p k) + f k (Poly_Mapping.lookup q k))" | 
| 1044 | by(rule sum.cong)(simp_all add: hom_plus) | |
| 1045 | also have "\<dots> = (\<Sum>k\<in>?A. f k (Poly_Mapping.lookup p k)) + (\<Sum>k\<in>?A. f k (Poly_Mapping.lookup q k))" | |
| 1046 | (is "_ = ?p' + ?q'") | |
| 1047 | by(simp add: sum.distrib) | |
| 1048 | also have "?p' = ?p" | |
| 1049 | by (simp add: hom_0 in_keys_iff sum.mono_neutral_cong_right) | |
| 1050 | also have "?q' = ?q" | |
| 1051 | by (simp add: hom_0 in_keys_iff sum.mono_neutral_cong_right) | |
| 1052 | finally show ?thesis . | |
| 1053 | qed | |
| 1054 | ||
| 1055 | subsection \<open>Degree\<close> | |
| 1056 | ||
| 1057 | definition degree :: "(nat \<Rightarrow>\<^sub>0 'a::zero) \<Rightarrow> nat" | |
| 1058 | where | |
| 1059 | "degree f = Max (insert 0 (Suc ` keys f))" | |
| 1060 | ||
| 1061 | lemma degree_zero [simp]: | |
| 1062 | "degree 0 = 0" | |
| 1063 | unfolding degree_def by transfer simp | |
| 1064 | ||
| 1065 | lemma degree_one [simp]: | |
| 1066 | "degree 1 = 1" | |
| 1067 | unfolding degree_def by transfer simp | |
| 1068 | ||
| 1069 | lemma degree_single_zero [simp]: | |
| 1070 | "degree (single k 0) = 0" | |
| 1071 | unfolding degree_def by transfer simp | |
| 1072 | ||
| 1073 | lemma degree_single_not_zero [simp]: | |
| 1074 | "v \<noteq> 0 \<Longrightarrow> degree (single k v) = Suc k" | |
| 1075 | unfolding degree_def by transfer simp | |
| 1076 | ||
| 1077 | lemma degree_zero_iff [simp]: | |
| 1078 | "degree f = 0 \<longleftrightarrow> f = 0" | |
| 1079 | unfolding degree_def proof transfer | |
| 1080 | fix f :: "nat \<Rightarrow> 'a" | |
| 1081 |   assume "finite {n. f n \<noteq> 0}"
 | |
| 1082 |   then have fin: "finite (insert 0 (Suc ` {n. f n \<noteq> 0}))" by auto
 | |
| 1083 |   show "Max (insert 0 (Suc ` {n. f n \<noteq> 0})) = 0 \<longleftrightarrow> f = (\<lambda>n. 0)" (is "?P \<longleftrightarrow> ?Q")
 | |
| 1084 | proof | |
| 1085 | assume ?P | |
| 1086 |     have "{n. f n \<noteq> 0} = {}"
 | |
| 1087 | proof (rule ccontr) | |
| 1088 |       assume "{n. f n \<noteq> 0} \<noteq> {}"
 | |
| 1089 |       then obtain n where "n \<in> {n. f n \<noteq> 0}" by blast
 | |
| 1090 |       then have "{n. f n \<noteq> 0} = insert n {n. f n \<noteq> 0}" by auto
 | |
| 1091 |       then have "Suc ` {n. f n \<noteq> 0} = insert (Suc n) (Suc ` {n. f n \<noteq> 0})" by auto
 | |
| 1092 |       with \<open>?P\<close> have "Max (insert 0 (insert (Suc n) (Suc ` {n. f n \<noteq> 0}))) = 0" by simp
 | |
| 1093 |       then have "Max (insert (Suc n) (insert 0 (Suc ` {n. f n \<noteq> 0}))) = 0"
 | |
| 1094 | by (simp add: insert_commute) | |
| 1095 |       with fin have "max (Suc n) (Max (insert 0 (Suc ` {n. f n \<noteq> 0}))) = 0"
 | |
| 1096 | by simp | |
| 1097 | then show False by simp | |
| 1098 | qed | |
| 1099 | then show ?Q by (simp add: fun_eq_iff) | |
| 1100 | next | |
| 1101 | assume ?Q then show ?P by simp | |
| 1102 | qed | |
| 1103 | qed | |
| 1104 | ||
| 1105 | lemma degree_greater_zero_in_keys: | |
| 1106 | assumes "0 < degree f" | |
| 1107 | shows "degree f - 1 \<in> keys f" | |
| 1108 | proof - | |
| 1109 |   from assms have "keys f \<noteq> {}"
 | |
| 80095 | 1110 | by (auto simp: degree_def) | 
| 70043 | 1111 | then show ?thesis unfolding degree_def | 
| 1112 | by (simp add: mono_Max_commute [symmetric] mono_Suc) | |
| 1113 | qed | |
| 1114 | ||
| 1115 | lemma in_keys_less_degree: | |
| 1116 | "n \<in> keys f \<Longrightarrow> n < degree f" | |
| 80095 | 1117 | unfolding degree_def by transfer (auto simp: Max_gr_iff) | 
| 70043 | 1118 | |
| 1119 | lemma beyond_degree_lookup_zero: | |
| 1120 | "degree f \<le> n \<Longrightarrow> lookup f n = 0" | |
| 1121 | unfolding degree_def by transfer auto | |
| 1122 | ||
| 1123 | lemma degree_add: | |
| 1124 | "degree (f + g) \<le> max (degree f) (Poly_Mapping.degree g)" | |
| 1125 | unfolding degree_def proof transfer | |
| 1126 | fix f g :: "nat \<Rightarrow> 'a" | |
| 1127 |   assume f: "finite {x. f x \<noteq> 0}"
 | |
| 1128 |   assume g: "finite {x. g x \<noteq> 0}"
 | |
| 1129 |   let ?f = "Max (insert 0 (Suc ` {k. f k \<noteq> 0}))"
 | |
| 1130 |   let ?g = "Max (insert 0 (Suc ` {k. g k \<noteq> 0}))"
 | |
| 1131 |   have "Max (insert 0 (Suc ` {k. f k + g k \<noteq> 0})) \<le> Max (insert 0 (Suc ` ({k. f k \<noteq> 0} \<union> {k. g k \<noteq> 0})))"
 | |
| 1132 | by (rule Max.subset_imp) (insert f g, auto) | |
| 1133 | also have "\<dots> = max ?f ?g" | |
| 1134 | using f g by (simp_all add: image_Un Max_Un [symmetric]) | |
| 1135 |   finally show "Max (insert 0 (Suc ` {k. f k + g k \<noteq> 0}))
 | |
| 1136 |     \<le> max (Max (insert 0 (Suc ` {k. f k \<noteq> 0}))) (Max (insert 0 (Suc ` {k. g k \<noteq> 0})))"
 | |
| 1137 | . | |
| 1138 | qed | |
| 1139 | ||
| 1140 | lemma sorted_list_of_set_keys: | |
| 1141 | "sorted_list_of_set (keys f) = filter (\<lambda>k. k \<in> keys f) [0..<degree f]" (is "_ = ?r") | |
| 1142 | proof - | |
| 1143 | have "keys f = set ?r" | |
| 1144 | by (auto dest: in_keys_less_degree) | |
| 1145 | moreover have "sorted_list_of_set (set ?r) = ?r" | |
| 1146 | unfolding sorted_list_of_set_sort_remdups | |
| 1147 | by (simp add: remdups_filter filter_sort [symmetric]) | |
| 1148 | ultimately show ?thesis by simp | |
| 1149 | qed | |
| 1150 | ||
| 1151 | ||
| 1152 | subsection \<open>Inductive structure\<close> | |
| 1153 | ||
| 1154 | lift_definition update :: "'a \<Rightarrow> 'b \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b::zero) \<Rightarrow> 'a \<Rightarrow>\<^sub>0 'b"
 | |
| 1155 | is "\<lambda>k v f. f(k := v)" | |
| 1156 | proof - | |
| 1157 | fix f :: "'a \<Rightarrow> 'b" and k' v | |
| 1158 |   assume "finite {k. f k \<noteq> 0}"
 | |
| 1159 |   then have "finite (insert k' {k. f k \<noteq> 0})"
 | |
| 1160 | by simp | |
| 1161 |   then show "finite {k. (f(k' := v)) k \<noteq> 0}"
 | |
| 1162 | by (rule rev_finite_subset) auto | |
| 1163 | qed | |
| 1164 | ||
| 1165 | lemma update_induct [case_names const update]: | |
| 1166 | assumes const': "P 0" | |
| 1167 | assumes update': "\<And>f a b. a \<notin> keys f \<Longrightarrow> b \<noteq> 0 \<Longrightarrow> P f \<Longrightarrow> P (update a b f)" | |
| 1168 | shows "P f" | |
| 1169 | proof - | |
| 1170 |   obtain g where "f = Abs_poly_mapping g" and "finite {a. g a \<noteq> 0}"
 | |
| 1171 | by (cases f) simp_all | |
| 1172 | define Q where "Q g = P (Abs_poly_mapping g)" for g | |
| 1173 |   from \<open>finite {a. g a \<noteq> 0}\<close> have "Q g"
 | |
| 1174 | proof (induct g rule: finite_update_induct) | |
| 1175 | case const with const' Q_def show ?case | |
| 1176 | by simp | |
| 1177 | next | |
| 1178 | case (update a b g) | |
| 1179 |     from \<open>finite {a. g a \<noteq> 0}\<close> \<open>g a = 0\<close> have "a \<notin> keys (Abs_poly_mapping g)"
 | |
| 1180 | by (simp add: Abs_poly_mapping_inverse keys.rep_eq) | |
| 1181 | moreover note \<open>b \<noteq> 0\<close> | |
| 1182 | moreover from \<open>Q g\<close> have "P (Abs_poly_mapping g)" | |
| 1183 | by (simp add: Q_def) | |
| 1184 | ultimately have "P (update a b (Abs_poly_mapping g))" | |
| 1185 | by (rule update') | |
| 1186 |     also from \<open>finite {a. g a \<noteq> 0}\<close>
 | |
| 1187 | have "update a b (Abs_poly_mapping g) = Abs_poly_mapping (g(a := b))" | |
| 1188 | by (simp add: update.abs_eq eq_onp_same_args) | |
| 1189 | finally show ?case | |
| 1190 | by (simp add: Q_def fun_upd_def) | |
| 1191 | qed | |
| 1192 | then show ?thesis by (simp add: Q_def \<open>f = Abs_poly_mapping g\<close>) | |
| 1193 | qed | |
| 1194 | ||
| 1195 | lemma lookup_update: | |
| 1196 | "lookup (update k v f) k' = (if k = k' then v else lookup f k')" | |
| 1197 | by transfer simp | |
| 1198 | ||
| 1199 | lemma keys_update: | |
| 1200 |   "keys (update k v f) = (if v = 0 then keys f - {k} else insert k (keys f))"
 | |
| 1201 | by transfer auto | |
| 1202 | ||
| 1203 | ||
| 1204 | subsection \<open>Quasi-functorial structure\<close> | |
| 1205 | ||
| 1206 | lift_definition map :: "('b::zero \<Rightarrow> 'c::zero)
 | |
| 1207 |   \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'c::zero)"
 | |
| 1208 | is "\<lambda>g f k. g (f k) when f k \<noteq> 0" | |
| 1209 | by simp | |
| 1210 | ||
| 1211 | context | |
| 1212 | fixes f :: "'b \<Rightarrow> 'a" | |
| 1213 | assumes inj_f: "inj f" | |
| 1214 | begin | |
| 1215 | ||
| 1216 | lift_definition map_key :: "('a \<Rightarrow>\<^sub>0 'c::zero) \<Rightarrow> 'b \<Rightarrow>\<^sub>0 'c"
 | |
| 1217 | is "\<lambda>p. p \<circ> f" | |
| 1218 | proof - | |
| 1219 | fix g :: "'c \<Rightarrow> 'd" and p :: "'a \<Rightarrow> 'c" | |
| 1220 |   assume "finite {x. p x \<noteq> 0}"
 | |
| 1221 |   hence "finite (f ` {y. p (f y) \<noteq> 0})"
 | |
| 1222 | by(rule finite_subset[rotated]) auto | |
| 1223 |   thus "finite {x. (p \<circ> f) x \<noteq> 0}" unfolding o_def
 | |
| 1224 | by(rule finite_imageD)(rule subset_inj_on[OF inj_f], simp) | |
| 1225 | qed | |
| 1226 | ||
| 1227 | end | |
| 1228 | ||
| 1229 | lemma map_key_compose: | |
| 1230 | assumes [transfer_rule]: "inj f" "inj g" | |
| 1231 | shows "map_key f (map_key g p) = map_key (g \<circ> f) p" | |
| 1232 | proof - | |
| 1233 | from assms have [transfer_rule]: "inj (g \<circ> f)" | |
| 1234 | by(simp add: inj_compose) | |
| 1235 | show ?thesis by transfer(simp add: o_assoc) | |
| 1236 | qed | |
| 1237 | ||
| 1238 | lemma map_key_id: | |
| 1239 | "map_key (\<lambda>x. x) p = p" | |
| 1240 | proof - | |
| 1241 | have [transfer_rule]: "inj (\<lambda>x. x)" by simp | |
| 1242 | show ?thesis by transfer(simp add: o_def) | |
| 1243 | qed | |
| 1244 | ||
| 1245 | context | |
| 1246 | fixes f :: "'a \<Rightarrow> 'b" | |
| 1247 | assumes inj_f [transfer_rule]: "inj f" | |
| 1248 | begin | |
| 1249 | ||
| 1250 | lemma map_key_map: | |
| 1251 | "map_key f (map g p) = map g (map_key f p)" | |
| 1252 | by transfer (simp add: fun_eq_iff) | |
| 1253 | ||
| 1254 | lemma map_key_plus: | |
| 1255 | "map_key f (p + q) = map_key f p + map_key f q" | |
| 1256 | by transfer (simp add: fun_eq_iff) | |
| 1257 | ||
| 1258 | lemma keys_map_key: | |
| 1259 | "keys (map_key f p) = f -` keys p" | |
| 1260 | by transfer auto | |
| 1261 | ||
| 1262 | lemma map_key_zero [simp]: | |
| 1263 | "map_key f 0 = 0" | |
| 1264 | by transfer (simp add: fun_eq_iff) | |
| 1265 | ||
| 1266 | lemma map_key_single [simp]: | |
| 1267 | "map_key f (single (f k) v) = single k v" | |
| 1268 | by transfer (simp add: fun_eq_iff inj_onD [OF inj_f] when_def) | |
| 1269 | ||
| 1270 | end | |
| 1271 | ||
| 1272 | lemma mult_map_scale_conv_mult: "map ((*) s) p = single 0 s * p" | |
| 1273 | proof(transfer fixing: s) | |
| 1274 | fix p :: "'a \<Rightarrow> 'b" | |
| 1275 |   assume *: "finite {x. p x \<noteq> 0}"
 | |
| 1276 |   { fix x
 | |
| 1277 | have "prod_fun (\<lambda>k'. s when 0 = k') p x = | |
| 1278 | (\<Sum>l :: 'a. if l = 0 then s * (\<Sum>q. p q when x = q) else 0)" | |
| 80095 | 1279 | by(auto simp: prod_fun_def when_def intro: Sum_any.cong simp del: Sum_any.delta) | 
| 70043 | 1280 | also have "\<dots> = (\<lambda>k. s * p k when p k \<noteq> 0) x" by(simp add: when_def) | 
| 1281 | also note calculation } | |
| 1282 | then show "(\<lambda>k. s * p k when p k \<noteq> 0) = prod_fun (\<lambda>k'. s when 0 = k') p" | |
| 1283 | by(simp add: fun_eq_iff) | |
| 1284 | qed | |
| 1285 | ||
| 1286 | lemma map_single [simp]: | |
| 1287 | "(c = 0 \<Longrightarrow> f 0 = 0) \<Longrightarrow> map f (single x c) = single x (f c)" | |
| 80095 | 1288 | by transfer(auto simp: fun_eq_iff when_def) | 
| 70043 | 1289 | |
| 1290 | lemma map_eq_zero_iff: "map f p = 0 \<longleftrightarrow> (\<forall>k \<in> keys p. f (lookup p k) = 0)" | |
| 80095 | 1291 | by transfer(auto simp: fun_eq_iff when_def) | 
| 70043 | 1292 | |
| 1293 | subsection \<open>Canonical dense representation of @{typ "nat \<Rightarrow>\<^sub>0 'a"}\<close>
 | |
| 1294 | ||
| 1295 | abbreviation no_trailing_zeros :: "'a :: zero list \<Rightarrow> bool" | |
| 1296 | where | |
| 1297 | "no_trailing_zeros \<equiv> no_trailing ((=) 0)" | |
| 1298 | ||
| 1299 | lift_definition "nth" :: "'a list \<Rightarrow> (nat \<Rightarrow>\<^sub>0 'a::zero)" | |
| 1300 | is "nth_default 0" | |
| 1301 | by (fact finite_nth_default_neq_default) | |
| 1302 | ||
| 1303 | text \<open> | |
| 1304 | The opposite direction is directly specified on (later) | |
| 1305 | type \<open>nat_mapping\<close>. | |
| 1306 | \<close> | |
| 1307 | ||
| 1308 | lemma nth_Nil [simp]: | |
| 1309 | "nth [] = 0" | |
| 1310 | by transfer (simp add: fun_eq_iff) | |
| 1311 | ||
| 1312 | lemma nth_singleton [simp]: | |
| 1313 | "nth [v] = single 0 v" | |
| 1314 | proof (transfer, rule ext) | |
| 1315 | fix n :: nat and v :: 'a | |
| 1316 | show "nth_default 0 [v] n = (v when 0 = n)" | |
| 80095 | 1317 | by (auto simp: nth_default_def nth_append) | 
| 70043 | 1318 | qed | 
| 1319 | ||
| 1320 | lemma nth_replicate [simp]: | |
| 1321 | "nth (replicate n 0 @ [v]) = single n v" | |
| 1322 | proof (transfer, rule ext) | |
| 1323 | fix m n :: nat and v :: 'a | |
| 1324 | show "nth_default 0 (replicate n 0 @ [v]) m = (v when n = m)" | |
| 80095 | 1325 | by (auto simp: nth_default_def nth_append) | 
| 70043 | 1326 | qed | 
| 1327 | ||
| 1328 | lemma nth_strip_while [simp]: | |
| 1329 | "nth (strip_while ((=) 0) xs) = nth xs" | |
| 1330 | by transfer (fact nth_default_strip_while_dflt) | |
| 1331 | ||
| 1332 | lemma nth_strip_while' [simp]: | |
| 1333 | "nth (strip_while (\<lambda>k. k = 0) xs) = nth xs" | |
| 1334 | by (subst eq_commute) (fact nth_strip_while) | |
| 1335 | ||
| 1336 | lemma nth_eq_iff: | |
| 1337 | "nth xs = nth ys \<longleftrightarrow> strip_while (HOL.eq 0) xs = strip_while (HOL.eq 0) ys" | |
| 1338 | by transfer (simp add: nth_default_eq_iff) | |
| 1339 | ||
| 1340 | lemma lookup_nth [simp]: | |
| 1341 | "lookup (nth xs) = nth_default 0 xs" | |
| 1342 | by (fact nth.rep_eq) | |
| 1343 | ||
| 1344 | lemma keys_nth [simp]: | |
| 1345 |   "keys (nth xs) =  fst ` {(n, v) \<in> set (enumerate 0 xs). v \<noteq> 0}"
 | |
| 1346 | proof transfer | |
| 1347 | fix xs :: "'a list" | |
| 1348 |   { fix n
 | |
| 1349 | assume "nth_default 0 xs n \<noteq> 0" | |
| 1350 | then have "n < length xs" and "xs ! n \<noteq> 0" | |
| 80095 | 1351 | by (auto simp: nth_default_def split: if_splits) | 
| 70043 | 1352 |     then have "(n, xs ! n) \<in> {(n, v). (n, v) \<in> set (enumerate 0 xs) \<and> v \<noteq> 0}" (is "?x \<in> ?A")
 | 
| 80095 | 1353 | by (auto simp: in_set_conv_nth enumerate_eq_zip) | 
| 70043 | 1354 | then have "fst ?x \<in> fst ` ?A" | 
| 1355 | by blast | |
| 1356 |     then have "n \<in> fst ` {(n, v). (n, v) \<in> set (enumerate 0 xs) \<and> v \<noteq> 0}"
 | |
| 1357 | by simp | |
| 1358 | } | |
| 1359 |   then show "{k. nth_default 0 xs k \<noteq> 0} = fst ` {(n, v). (n, v) \<in> set (enumerate 0 xs) \<and> v \<noteq> 0}"
 | |
| 80095 | 1360 | by (auto simp: in_enumerate_iff_nth_default_eq) | 
| 70043 | 1361 | qed | 
| 1362 | ||
| 1363 | lemma range_nth [simp]: | |
| 1364 |   "range (nth xs) = set xs - {0}"
 | |
| 1365 | by transfer simp | |
| 1366 | ||
| 1367 | lemma degree_nth: | |
| 1368 | "no_trailing_zeros xs \<Longrightarrow> degree (nth xs) = length xs" | |
| 1369 | unfolding degree_def proof transfer | |
| 1370 | fix xs :: "'a list" | |
| 1371 | assume *: "no_trailing_zeros xs" | |
| 1372 |   let ?A = "{n. nth_default 0 xs n \<noteq> 0}"
 | |
| 1373 | let ?f = "nth_default 0 xs" | |
| 1374 |   let ?bound = "Max (insert 0 (Suc ` {n. ?f n \<noteq> 0}))"
 | |
| 1375 | show "?bound = length xs" | |
| 1376 | proof (cases "xs = []") | |
| 1377 | case False | |
| 1378 | with * obtain n where n: "n < length xs" "xs ! n \<noteq> 0" | |
| 1379 | by (fastforce simp add: no_trailing_unfold last_conv_nth neq_Nil_conv) | |
| 1380 |     then have "?bound = Max (Suc ` {k. (k < length xs \<longrightarrow> xs ! k \<noteq> (0::'a)) \<and> k < length xs})"
 | |
| 80095 | 1381 | by (subst Max_insert) (auto simp: nth_default_def) | 
| 70043 | 1382 |     also let ?A = "{k. k < length xs \<and> xs ! k \<noteq> 0}"
 | 
| 1383 |     have "{k. (k < length xs \<longrightarrow> xs ! k \<noteq> (0::'a)) \<and> k < length xs} = ?A" by auto
 | |
| 1384 | also have "Max (Suc ` ?A) = Suc (Max ?A)" using n | |
| 80095 | 1385 | by (subst mono_Max_commute [where f = Suc, symmetric]) (auto simp: mono_Suc) | 
| 70043 | 1386 |     also {
 | 
| 1387 | have "Max ?A \<in> ?A" using n Max_in [of ?A] by fastforce | |
| 1388 | hence "Suc (Max ?A) \<le> length xs" by simp | |
| 1389 | moreover from * False have "length xs - 1 \<in> ?A" | |
| 80095 | 1390 | by(auto simp: no_trailing_unfold last_conv_nth) | 
| 70043 | 1391 | hence "length xs - 1 \<le> Max ?A" using Max_ge[of ?A "length xs - 1"] by auto | 
| 1392 | hence "length xs \<le> Suc (Max ?A)" by simp | |
| 1393 | ultimately have "Suc (Max ?A) = length xs" by simp } | |
| 1394 | finally show ?thesis . | |
| 1395 | qed simp | |
| 1396 | qed | |
| 1397 | ||
| 1398 | lemma nth_trailing_zeros [simp]: | |
| 1399 | "nth (xs @ replicate n 0) = nth xs" | |
| 1400 | by transfer simp | |
| 1401 | ||
| 1402 | lemma nth_idem: | |
| 1403 | "nth (List.map (lookup f) [0..<degree f]) = f" | |
| 1404 | unfolding degree_def by transfer | |
| 80095 | 1405 | (auto simp: nth_default_def fun_eq_iff not_less) | 
| 70043 | 1406 | |
| 1407 | lemma nth_idem_bound: | |
| 1408 | assumes "degree f \<le> n" | |
| 1409 | shows "nth (List.map (lookup f) [0..<n]) = f" | |
| 1410 | proof - | |
| 1411 | from assms obtain m where "n = degree f + m" | |
| 1412 | by (blast dest: le_Suc_ex) | |
| 1413 | then have "[0..<n] = [0..<degree f] @ [degree f..<degree f + m]" | |
| 1414 | by (simp add: upt_add_eq_append [of 0]) | |
| 1415 | moreover have "List.map (lookup f) [degree f..<degree f + m] = replicate m 0" | |
| 80095 | 1416 | by (rule replicate_eqI) (auto simp: beyond_degree_lookup_zero) | 
| 70043 | 1417 | ultimately show ?thesis by (simp add: nth_idem) | 
| 1418 | qed | |
| 1419 | ||
| 1420 | ||
| 1421 | subsection \<open>Canonical sparse representation of @{typ "'a \<Rightarrow>\<^sub>0 'b"}\<close>
 | |
| 1422 | ||
| 1423 | lift_definition the_value :: "('a \<times> 'b) list \<Rightarrow> 'a \<Rightarrow>\<^sub>0 'b::zero"
 | |
| 1424 | is "\<lambda>xs k. case map_of xs k of None \<Rightarrow> 0 | Some v \<Rightarrow> v" | |
| 1425 | proof - | |
| 1426 |   fix xs :: "('a \<times> 'b) list"
 | |
| 1427 |   have fin: "finite {k. \<exists>v. map_of xs k = Some v}"
 | |
| 1428 | using finite_dom_map_of [of xs] unfolding dom_def by auto | |
| 1429 |   then show "finite {k. (case map_of xs k of None \<Rightarrow> 0 | Some v \<Rightarrow> v) \<noteq> 0}"
 | |
| 1430 | using fin by (simp split: option.split) | |
| 1431 | qed | |
| 1432 | ||
| 1433 | definition items :: "('a::linorder \<Rightarrow>\<^sub>0 'b::zero) \<Rightarrow> ('a \<times> 'b) list"
 | |
| 1434 | where | |
| 1435 | "items f = List.map (\<lambda>k. (k, lookup f k)) (sorted_list_of_set (keys f))" | |
| 1436 | ||
| 1437 | text \<open> | |
| 1438 | For the canonical sparse representation we provide both | |
| 1439 | directions of morphisms since the specification of | |
| 1440 | ordered association lists in theory \<open>OAList\<close> | |
| 1441 |   will support arbitrary linear orders @{class linorder}
 | |
| 1442 |   as keys, not just natural numbers @{typ nat}.
 | |
| 1443 | \<close> | |
| 1444 | ||
| 1445 | lemma the_value_items [simp]: | |
| 1446 | "the_value (items f) = f" | |
| 1447 | unfolding items_def | |
| 1448 | by transfer (simp add: fun_eq_iff map_of_map_restrict restrict_map_def) | |
| 1449 | ||
| 1450 | lemma lookup_the_value: | |
| 1451 | "lookup (the_value xs) k = (case map_of xs k of None \<Rightarrow> 0 | Some v \<Rightarrow> v)" | |
| 1452 | by transfer rule | |
| 1453 | ||
| 1454 | lemma items_the_value: | |
| 1455 | assumes "sorted (List.map fst xs)" and "distinct (List.map fst xs)" and "0 \<notin> snd ` set xs" | |
| 1456 | shows "items (the_value xs) = xs" | |
| 1457 | proof - | |
| 1458 | from assms have "sorted_list_of_set (set (List.map fst xs)) = List.map fst xs" | |
| 76484 
defaa0b17424
generalized sorted_sort_id to sort_key_id_if_sorted
 nipkow parents: 
75455diff
changeset | 1459 | unfolding sorted_list_of_set_sort_remdups by (simp add: distinct_remdups_id sort_key_id_if_sorted) | 
| 70043 | 1460 | moreover from assms have "keys (the_value xs) = fst ` set xs" | 
| 80095 | 1461 | by transfer (auto simp: image_def split: option.split dest: set_map_of_compr) | 
| 70043 | 1462 | ultimately show ?thesis | 
| 1463 | unfolding items_def using assms | |
| 80095 | 1464 | by (auto simp: lookup_the_value intro: map_idI) | 
| 70043 | 1465 | qed | 
| 1466 | ||
| 1467 | lemma the_value_Nil [simp]: | |
| 1468 | "the_value [] = 0" | |
| 1469 | by transfer (simp add: fun_eq_iff) | |
| 1470 | ||
| 1471 | lemma the_value_Cons [simp]: | |
| 1472 | "the_value (x # xs) = update (fst x) (snd x) (the_value xs)" | |
| 1473 | by transfer (simp add: fun_eq_iff) | |
| 1474 | ||
| 1475 | lemma items_zero [simp]: | |
| 1476 | "items 0 = []" | |
| 1477 | unfolding items_def by simp | |
| 1478 | ||
| 1479 | lemma items_one [simp]: | |
| 1480 | "items 1 = [(0, 1)]" | |
| 1481 | unfolding items_def by transfer simp | |
| 1482 | ||
| 1483 | lemma items_single [simp]: | |
| 1484 | "items (single k v) = (if v = 0 then [] else [(k, v)])" | |
| 1485 | unfolding items_def by simp | |
| 1486 | ||
| 1487 | lemma in_set_items_iff [simp]: | |
| 1488 | "(k, v) \<in> set (items f) \<longleftrightarrow> k \<in> keys f \<and> lookup f k = v" | |
| 1489 | unfolding items_def by transfer auto | |
| 1490 | ||
| 1491 | ||
| 1492 | subsection \<open>Size estimation\<close> | |
| 1493 | ||
| 1494 | context | |
| 1495 | fixes f :: "'a \<Rightarrow> nat" | |
| 1496 | and g :: "'b :: zero \<Rightarrow> nat" | |
| 1497 | begin | |
| 1498 | ||
| 1499 | definition poly_mapping_size :: "('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> nat"
 | |
| 1500 | where | |
| 1501 | "poly_mapping_size m = g 0 + (\<Sum>k \<in> keys m. Suc (f k + g (lookup m k)))" | |
| 1502 | ||
| 1503 | lemma poly_mapping_size_0 [simp]: | |
| 1504 | "poly_mapping_size 0 = g 0" | |
| 1505 | by (simp add: poly_mapping_size_def) | |
| 1506 | ||
| 1507 | lemma poly_mapping_size_single [simp]: | |
| 1508 | "poly_mapping_size (single k v) = (if v = 0 then g 0 else g 0 + f k + g v + 1)" | |
| 1509 | unfolding poly_mapping_size_def by transfer simp | |
| 1510 | ||
| 1511 | lemma keys_less_poly_mapping_size: | |
| 1512 | "k \<in> keys m \<Longrightarrow> f k + g (lookup m k) < poly_mapping_size m" | |
| 1513 | unfolding poly_mapping_size_def | |
| 1514 | proof transfer | |
| 1515 | fix k :: 'a and m :: "'a \<Rightarrow> 'b" and f :: "'a \<Rightarrow> nat" and g | |
| 1516 |   let ?keys = "{k. m k \<noteq> 0}"
 | |
| 1517 | assume *: "finite ?keys" "k \<in> ?keys" | |
| 1518 | then have "f k + g (m k) = (\<Sum>k' \<in> ?keys. f k' + g (m k') when k' = k)" | |
| 1519 | by (simp add: sum.delta when_def) | |
| 1520 | also have "\<dots> < (\<Sum>k' \<in> ?keys. Suc (f k' + g (m k')))" using * | |
| 80095 | 1521 | by (intro sum_strict_mono) (auto simp: when_def) | 
| 70043 | 1522 | also have "\<dots> \<le> g 0 + \<dots>" by simp | 
| 1523 | finally have "f k + g (m k) < \<dots>" . | |
| 1524 | then show "f k + g (m k) < g 0 + (\<Sum>k | m k \<noteq> 0. Suc (f k + g (m k)))" | |
| 1525 | by simp | |
| 1526 | qed | |
| 1527 | ||
| 1528 | lemma lookup_le_poly_mapping_size: | |
| 1529 | "g (lookup m k) \<le> poly_mapping_size m" | |
| 1530 | proof (cases "k \<in> keys m") | |
| 1531 | case True | |
| 1532 | with keys_less_poly_mapping_size [of k m] | |
| 1533 | show ?thesis by simp | |
| 1534 | next | |
| 1535 | case False | |
| 1536 | then show ?thesis | |
| 1537 | by (simp add: Poly_Mapping.poly_mapping_size_def in_keys_iff) | |
| 1538 | qed | |
| 1539 | ||
| 1540 | lemma poly_mapping_size_estimation: | |
| 1541 | "k \<in> keys m \<Longrightarrow> y \<le> f k + g (lookup m k) \<Longrightarrow> y < poly_mapping_size m" | |
| 1542 | using keys_less_poly_mapping_size by (auto intro: le_less_trans) | |
| 1543 | ||
| 1544 | lemma poly_mapping_size_estimation2: | |
| 1545 | assumes "v \<in> range m" and "y \<le> g v" | |
| 1546 | shows "y < poly_mapping_size m" | |
| 1547 | proof - | |
| 1548 | from assms obtain k where *: "lookup m k = v" "v \<noteq> 0" | |
| 1549 | by transfer blast | |
| 1550 | from * have "k \<in> keys m" | |
| 1551 | by (simp add: in_keys_iff) | |
| 1552 | then show ?thesis | |
| 1553 | proof (rule poly_mapping_size_estimation) | |
| 1554 | from assms * have "y \<le> g (lookup m k)" | |
| 1555 | by simp | |
| 1556 | then show "y \<le> f k + g (lookup m k)" | |
| 1557 | by simp | |
| 1558 | qed | |
| 1559 | qed | |
| 1560 | ||
| 1561 | end | |
| 1562 | ||
| 1563 | lemma poly_mapping_size_one [simp]: | |
| 1564 | "poly_mapping_size f g 1 = g 0 + f 0 + g 1 + 1" | |
| 1565 | unfolding poly_mapping_size_def by transfer simp | |
| 1566 | ||
| 1567 | lemma poly_mapping_size_cong [fundef_cong]: | |
| 1568 | "m = m' \<Longrightarrow> g 0 = g' 0 \<Longrightarrow> (\<And>k. k \<in> keys m' \<Longrightarrow> f k = f' k) | |
| 1569 | \<Longrightarrow> (\<And>v. v \<in> range m' \<Longrightarrow> g v = g' v) | |
| 1570 | \<Longrightarrow> poly_mapping_size f g m = poly_mapping_size f' g' m'" | |
| 80095 | 1571 | by (auto simp: poly_mapping_size_def intro!: sum.cong) | 
| 70043 | 1572 | |
| 1573 | instantiation poly_mapping :: (type, zero) size | |
| 1574 | begin | |
| 1575 | ||
| 1576 | definition "size = poly_mapping_size (\<lambda>_. 0) (\<lambda>_. 0)" | |
| 1577 | ||
| 1578 | instance .. | |
| 1579 | ||
| 1580 | end | |
| 1581 | ||
| 1582 | ||
| 1583 | subsection \<open>Further mapping operations and properties\<close> | |
| 1584 | ||
| 1585 | text \<open>It is like in algebra: there are many definitions, some are also used\<close> | |
| 1586 | ||
| 1587 | lift_definition mapp :: | |
| 1588 |   "('a \<Rightarrow> 'b :: zero \<Rightarrow> 'c :: zero) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'b) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 'c)"
 | |
| 1589 | is "\<lambda>f p k. (if k \<in> keys p then f k (lookup p k) else 0)" | |
| 1590 | by simp | |
| 1591 | ||
| 1592 | lemma mapp_cong [fundef_cong]: | |
| 1593 | "\<lbrakk> m = m'; \<And>k. k \<in> keys m' \<Longrightarrow> f k (lookup m' k) = f' k (lookup m' k) \<rbrakk> | |
| 1594 | \<Longrightarrow> mapp f m = mapp f' m'" | |
| 80095 | 1595 | by transfer (auto simp: fun_eq_iff) | 
| 70043 | 1596 | |
| 1597 | lemma lookup_mapp: | |
| 1598 | "lookup (mapp f p) k = (f k (lookup p k) when k \<in> keys p)" | |
| 1599 | by (simp add: mapp.rep_eq) | |
| 1600 | ||
| 1601 | lemma keys_mapp_subset: "keys (mapp f p) \<subseteq> keys p" | |
| 1602 | by (meson in_keys_iff mapp.rep_eq subsetI) | |
| 1603 | ||
| 1604 | subsection\<open>Free Abelian Groups Over a Type\<close> | |
| 1605 | ||
| 1606 | abbreviation frag_of :: "'a \<Rightarrow> 'a \<Rightarrow>\<^sub>0 int" | |
| 1607 | where "frag_of c \<equiv> Poly_Mapping.single c (1::int)" | |
| 1608 | ||
| 1609 | lemma lookup_frag_of [simp]: | |
| 1610 | "Poly_Mapping.lookup(frag_of c) = (\<lambda>x. if x = c then 1 else 0)" | |
| 1611 | by (force simp add: lookup_single_not_eq) | |
| 1612 | ||
| 1613 | lemma frag_of_nonzero [simp]: "frag_of a \<noteq> 0" | |
| 1614 | proof - | |
| 1615 | let ?f = "\<lambda>x. if x = a then 1 else (0::int)" | |
| 1616 | have "?f \<noteq> (\<lambda>x. 0::int)" | |
| 1617 | by (auto simp: fun_eq_iff) | |
| 1618 | then have "Poly_Mapping.lookup (Abs_poly_mapping ?f) \<noteq> Poly_Mapping.lookup (Abs_poly_mapping (\<lambda>x. 0))" | |
| 1619 | by fastforce | |
| 1620 | then show ?thesis | |
| 1621 | by (metis lookup_single_eq lookup_zero) | |
| 1622 | qed | |
| 1623 | ||
| 1624 | definition frag_cmul :: "int \<Rightarrow> ('a \<Rightarrow>\<^sub>0 int) \<Rightarrow> ('a \<Rightarrow>\<^sub>0 int)"
 | |
| 1625 | where "frag_cmul c a = Abs_poly_mapping (\<lambda>x. c * Poly_Mapping.lookup a x)" | |
| 1626 | ||
| 1627 | lemma frag_cmul_zero [simp]: "frag_cmul 0 x = 0" | |
| 1628 | by (simp add: frag_cmul_def) | |
| 1629 | ||
| 1630 | lemma frag_cmul_zero2 [simp]: "frag_cmul c 0 = 0" | |
| 1631 | by (simp add: frag_cmul_def) | |
| 1632 | ||
| 1633 | lemma frag_cmul_one [simp]: "frag_cmul 1 x = x" | |
| 1634 | by (auto simp: frag_cmul_def Poly_Mapping.poly_mapping.lookup_inverse) | |
| 1635 | ||
| 1636 | lemma frag_cmul_minus_one [simp]: "frag_cmul (-1) x = -x" | |
| 1637 | by (simp add: frag_cmul_def uminus_poly_mapping_def poly_mapping_eqI) | |
| 1638 | ||
| 1639 | lemma frag_cmul_cmul [simp]: "frag_cmul c (frag_cmul d x) = frag_cmul (c*d) x" | |
| 1640 | by (simp add: frag_cmul_def mult_ac) | |
| 1641 | ||
| 1642 | lemma lookup_frag_cmul [simp]: "poly_mapping.lookup (frag_cmul c x) i = c * poly_mapping.lookup x i" | |
| 1643 | by (simp add: frag_cmul_def) | |
| 1644 | ||
| 1645 | lemma minus_frag_cmul [simp]: "- frag_cmul k x = frag_cmul (-k) x" | |
| 1646 | by (simp add: poly_mapping_eqI) | |
| 1647 | ||
| 1648 | lemma keys_frag_of: "Poly_Mapping.keys(frag_of a) = {a}"
 | |
| 1649 | by simp | |
| 1650 | ||
| 1651 | lemma finite_cmul_nonzero: "finite {x. c * Poly_Mapping.lookup a x \<noteq> (0::int)}"
 | |
| 1652 | by simp | |
| 1653 | ||
| 1654 | lemma keys_cmul: "Poly_Mapping.keys(frag_cmul c a) \<subseteq> Poly_Mapping.keys a" | |
| 1655 | using finite_cmul_nonzero [of c a] | |
| 1656 | by (metis lookup_frag_cmul mult_zero_right not_in_keys_iff_lookup_eq_zero subsetI) | |
| 1657 | ||
| 1658 | ||
| 1659 | lemma keys_cmul_iff [iff]: "i \<in> Poly_Mapping.keys (frag_cmul c x) \<longleftrightarrow> i \<in> Poly_Mapping.keys x \<and> c \<noteq> 0" | |
| 1660 | by (metis in_keys_iff lookup_frag_cmul mult_eq_0_iff) | |
| 1661 | ||
| 1662 | lemma keys_minus [simp]: "Poly_Mapping.keys(-a) = Poly_Mapping.keys a" | |
| 73932 
fd21b4a93043
added opaque_combs and renamed hide_lams to opaque_lifting
 desharna parents: 
73655diff
changeset | 1663 | by (metis (no_types, opaque_lifting) in_keys_iff lookup_uminus neg_equal_0_iff_equal subsetI subset_antisym) | 
| 70043 | 1664 | |
| 1665 | lemma keys_diff: | |
| 1666 | "Poly_Mapping.keys(a - b) \<subseteq> Poly_Mapping.keys a \<union> Poly_Mapping.keys b" | |
| 80095 | 1667 | by (auto simp: in_keys_iff lookup_minus) | 
| 70043 | 1668 | |
| 1669 | lemma keys_eq_empty [simp]: "Poly_Mapping.keys c = {} \<longleftrightarrow> c = 0"
 | |
| 1670 | by (metis in_keys_iff keys_zero lookup_zero poly_mapping_eqI) | |
| 1671 | ||
| 1672 | lemma frag_cmul_eq_0_iff [simp]: "frag_cmul k c = 0 \<longleftrightarrow> k=0 \<or> c=0" | |
| 1673 | by auto (metis subsetI subset_antisym keys_cmul_iff keys_eq_empty) | |
| 1674 | ||
| 1675 | lemma frag_of_eq: "frag_of x = frag_of y \<longleftrightarrow> x = y" | |
| 1676 | by (metis lookup_single_eq lookup_single_not_eq zero_neq_one) | |
| 1677 | ||
| 1678 | lemma frag_cmul_distrib: "frag_cmul (c+d) a = frag_cmul c a + frag_cmul d a" | |
| 1679 | by (simp add: frag_cmul_def plus_poly_mapping_def int_distrib) | |
| 1680 | ||
| 1681 | lemma frag_cmul_distrib2: "frag_cmul c (a+b) = frag_cmul c a + frag_cmul c b" | |
| 1682 | proof - | |
| 1683 |   have "finite {x. poly_mapping.lookup a x + poly_mapping.lookup b x \<noteq> 0}"
 | |
| 1684 | using keys_add [of a b] | |
| 1685 | by (metis (no_types, lifting) finite_keys finite_subset keys.rep_eq lookup_add mem_Collect_eq subsetI) | |
| 1686 | then show ?thesis | |
| 1687 | by (simp add: frag_cmul_def plus_poly_mapping_def int_distrib) | |
| 1688 | qed | |
| 1689 | ||
| 1690 | lemma frag_cmul_diff_distrib: "frag_cmul (a - b) c = frag_cmul a c - frag_cmul b c" | |
| 1691 | by (auto simp: left_diff_distrib lookup_minus poly_mapping_eqI) | |
| 1692 | ||
| 1693 | lemma frag_cmul_sum: | |
| 1694 | "frag_cmul a (sum b I) = (\<Sum>i\<in>I. frag_cmul a (b i))" | |
| 1695 | proof (induction rule: infinite_finite_induct) | |
| 1696 | case (insert i I) | |
| 1697 | then show ?case | |
| 1698 | by (auto simp: algebra_simps frag_cmul_distrib2) | |
| 1699 | qed auto | |
| 1700 | ||
| 1701 | lemma keys_sum: "Poly_Mapping.keys(sum b I) \<subseteq> (\<Union>i \<in>I. Poly_Mapping.keys(b i))" | |
| 1702 | proof (induction I rule: infinite_finite_induct) | |
| 1703 | case (insert i I) | |
| 1704 | then show ?case | |
| 1705 | using keys_add [of "b i" "sum b I"] by auto | |
| 1706 | qed auto | |
| 1707 | ||
| 1708 | ||
| 1709 | definition frag_extend :: "('b \<Rightarrow> 'a \<Rightarrow>\<^sub>0 int) \<Rightarrow> ('b \<Rightarrow>\<^sub>0 int) \<Rightarrow> 'a \<Rightarrow>\<^sub>0 int"
 | |
| 1710 | where "frag_extend b x \<equiv> (\<Sum>i \<in> Poly_Mapping.keys x. frag_cmul (Poly_Mapping.lookup x i) (b i))" | |
| 1711 | ||
| 1712 | lemma frag_extend_0 [simp]: "frag_extend b 0 = 0" | |
| 1713 | by (simp add: frag_extend_def) | |
| 1714 | ||
| 1715 | lemma frag_extend_of [simp]: "frag_extend f (frag_of a) = f a" | |
| 1716 | by (simp add: frag_extend_def) | |
| 1717 | ||
| 1718 | lemma frag_extend_cmul: | |
| 1719 | "frag_extend f (frag_cmul c x) = frag_cmul c (frag_extend f x)" | |
| 1720 | by (auto simp: frag_extend_def frag_cmul_sum intro: sum.mono_neutral_cong_left) | |
| 1721 | ||
| 1722 | lemma frag_extend_minus: | |
| 1723 | "frag_extend f (- x) = - (frag_extend f x)" | |
| 1724 | using frag_extend_cmul [of f "-1"] by simp | |
| 1725 | ||
| 1726 | lemma frag_extend_add: | |
| 1727 | "frag_extend f (a+b) = (frag_extend f a) + (frag_extend f b)" | |
| 1728 | proof - | |
| 1729 | have *: "(\<Sum>i\<in>Poly_Mapping.keys a. frag_cmul (poly_mapping.lookup a i) (f i)) | |
| 1730 | = (\<Sum>i\<in>Poly_Mapping.keys a \<union> Poly_Mapping.keys b. frag_cmul (poly_mapping.lookup a i) (f i))" | |
| 1731 | "(\<Sum>i\<in>Poly_Mapping.keys b. frag_cmul (poly_mapping.lookup b i) (f i)) | |
| 1732 | = (\<Sum>i\<in>Poly_Mapping.keys a \<union> Poly_Mapping.keys b. frag_cmul (poly_mapping.lookup b i) (f i))" | |
| 1733 | by (auto simp: in_keys_iff intro: sum.mono_neutral_cong_left) | |
| 1734 | have "frag_extend f (a+b) = (\<Sum>i\<in>Poly_Mapping.keys (a + b). | |
| 1735 | frag_cmul (poly_mapping.lookup a i) (f i) + frag_cmul (poly_mapping.lookup b i) (f i)) " | |
| 1736 | by (auto simp: frag_extend_def Poly_Mapping.lookup_add frag_cmul_distrib) | |
| 1737 | also have "... = (\<Sum>i \<in> Poly_Mapping.keys a \<union> Poly_Mapping.keys b. frag_cmul (poly_mapping.lookup a i) (f i) | |
| 1738 | + frag_cmul (poly_mapping.lookup b i) (f i))" | |
| 80095 | 1739 | proof (rule sum.mono_neutral_cong_left) | 
| 1740 | show "\<forall>i\<in>keys a \<union> keys b - keys (a + b). | |
| 1741 | frag_cmul (lookup a i) (f i) + frag_cmul (lookup b i) (f i) = 0" | |
| 1742 | by (metis DiffD2 frag_cmul_distrib frag_cmul_zero in_keys_iff lookup_add) | |
| 1743 | qed (auto simp: keys_add) | |
| 70043 | 1744 | also have "... = (frag_extend f a) + (frag_extend f b)" | 
| 1745 | by (auto simp: * sum.distrib frag_extend_def) | |
| 1746 | finally show ?thesis . | |
| 1747 | qed | |
| 1748 | ||
| 1749 | lemma frag_extend_diff: | |
| 1750 | "frag_extend f (a-b) = (frag_extend f a) - (frag_extend f b)" | |
| 73932 
fd21b4a93043
added opaque_combs and renamed hide_lams to opaque_lifting
 desharna parents: 
73655diff
changeset | 1751 | by (metis (no_types, opaque_lifting) add_uminus_conv_diff frag_extend_add frag_extend_minus) | 
| 70043 | 1752 | |
| 1753 | lemma frag_extend_sum: | |
| 1754 | "finite I \<Longrightarrow> frag_extend f (\<Sum>i\<in>I. g i) = sum (frag_extend f o g) I" | |
| 1755 | by (induction I rule: finite_induct) (simp_all add: frag_extend_add) | |
| 1756 | ||
| 1757 | lemma frag_extend_eq: | |
| 1758 | "(\<And>f. f \<in> Poly_Mapping.keys c \<Longrightarrow> g f = h f) \<Longrightarrow> frag_extend g c = frag_extend h c" | |
| 1759 | by (simp add: frag_extend_def) | |
| 1760 | ||
| 1761 | lemma frag_extend_eq_0: | |
| 1762 | "(\<And>x. x \<in> Poly_Mapping.keys c \<Longrightarrow> f x = 0) \<Longrightarrow> frag_extend f c = 0" | |
| 1763 | by (simp add: frag_extend_def) | |
| 1764 | ||
| 1765 | lemma keys_frag_extend: "Poly_Mapping.keys(frag_extend f c) \<subseteq> (\<Union>x \<in> Poly_Mapping.keys c. Poly_Mapping.keys(f x))" | |
| 1766 | unfolding frag_extend_def | |
| 73655 
26a1d66b9077
tuned proofs --- avoid z3, which is absent on arm64-linux;
 wenzelm parents: 
70045diff
changeset | 1767 | using keys_sum by fastforce | 
| 70043 | 1768 | |
| 1769 | lemma frag_expansion: "a = frag_extend frag_of a" | |
| 1770 | proof - | |
| 1771 | have *: "finite I | |
| 1772 | \<Longrightarrow> Poly_Mapping.lookup (\<Sum>i\<in>I. frag_cmul (Poly_Mapping.lookup a i) (frag_of i)) j = | |
| 1773 | (if j \<in> I then Poly_Mapping.lookup a j else 0)" for I j | |
| 1774 | by (induction I rule: finite_induct) (auto simp: lookup_single lookup_add) | |
| 1775 | show ?thesis | |
| 1776 | unfolding frag_extend_def | |
| 1777 | by (rule poly_mapping_eqI) (fastforce simp add: in_keys_iff *) | |
| 1778 | qed | |
| 1779 | ||
| 1780 | lemma frag_closure_minus_cmul: | |
| 1781 | assumes "P 0" and P: "\<And>x y. \<lbrakk>P x; P y\<rbrakk> \<Longrightarrow> P(x - y)" "P c" | |
| 1782 | shows "P(frag_cmul k c)" | |
| 1783 | proof - | |
| 1784 | have "P (frag_cmul (int n) c)" for n | |
| 80095 | 1785 | proof (induction n) | 
| 1786 | case 0 | |
| 1787 | then show ?case | |
| 1788 | by (simp add: assms) | |
| 1789 | next | |
| 1790 | case (Suc n) | |
| 1791 | then show ?case | |
| 1792 | by (metis assms diff_0 diff_minus_eq_add frag_cmul_distrib frag_cmul_one of_nat_Suc) | |
| 1793 | qed | |
| 70043 | 1794 | then show ?thesis | 
| 73932 
fd21b4a93043
added opaque_combs and renamed hide_lams to opaque_lifting
 desharna parents: 
73655diff
changeset | 1795 | by (metis (no_types, opaque_lifting) add_diff_eq assms(2) diff_add_cancel frag_cmul_distrib int_diff_cases) | 
| 70043 | 1796 | qed | 
| 1797 | ||
| 1798 | lemma frag_induction [consumes 1, case_names zero one diff]: | |
| 1799 | assumes supp: "Poly_Mapping.keys c \<subseteq> S" | |
| 1800 | and 0: "P 0" and sing: "\<And>x. x \<in> S \<Longrightarrow> P(frag_of x)" | |
| 1801 | and diff: "\<And>a b. \<lbrakk>P a; P b\<rbrakk> \<Longrightarrow> P(a - b)" | |
| 1802 | shows "P c" | |
| 1803 | proof - | |
| 1804 | have "P (\<Sum>i\<in>I. frag_cmul (poly_mapping.lookup c i) (frag_of i))" | |
| 1805 | if "I \<subseteq> Poly_Mapping.keys c" for I | |
| 1806 | using finite_subset [OF that finite_keys [of c]] that supp | |
| 1807 | proof (induction I arbitrary: c rule: finite_induct) | |
| 1808 | case empty | |
| 1809 | then show ?case | |
| 1810 | by (auto simp: 0) | |
| 1811 | next | |
| 1812 | case (insert i I c) | |
| 1813 | have ab: "a+b = a - (0 - b)" for a b :: "'a \<Rightarrow>\<^sub>0 int" | |
| 1814 | by simp | |
| 1815 | have Pfrag: "P (frag_cmul (poly_mapping.lookup c i) (frag_of i))" | |
| 1816 | by (metis "0" diff frag_closure_minus_cmul insert.prems insert_subset sing subset_iff) | |
| 80095 | 1817 | with insert show ?case | 
| 1818 | by (metis (mono_tags, lifting) "0" ab diff insert_subset sum.insert) | |
| 70043 | 1819 | qed | 
| 1820 | then show ?thesis | |
| 80095 | 1821 | by (subst frag_expansion) (auto simp: frag_extend_def) | 
| 70043 | 1822 | qed | 
| 1823 | ||
| 1824 | lemma frag_extend_compose: | |
| 1825 | "frag_extend f (frag_extend (frag_of o g) c) = frag_extend (f o g) c" | |
| 1826 | using subset_UNIV | |
| 1827 | by (induction c rule: frag_induction) (auto simp: frag_extend_diff) | |
| 1828 | ||
| 1829 | lemma frag_split: | |
| 1830 | fixes c :: "'a \<Rightarrow>\<^sub>0 int" | |
| 1831 | assumes "Poly_Mapping.keys c \<subseteq> S \<union> T" | |
| 1832 | obtains d e where "Poly_Mapping.keys d \<subseteq> S" "Poly_Mapping.keys e \<subseteq> T" "d + e = c" | |
| 1833 | proof | |
| 1834 | let ?d = "frag_extend (\<lambda>f. if f \<in> S then frag_of f else 0) c" | |
| 1835 | let ?e = "frag_extend (\<lambda>f. if f \<in> S then 0 else frag_of f) c" | |
| 1836 | show "Poly_Mapping.keys ?d \<subseteq> S" "Poly_Mapping.keys ?e \<subseteq> T" | |
| 1837 | using assms by (auto intro!: order_trans [OF keys_frag_extend] split: if_split_asm) | |
| 1838 | show "?d + ?e = c" | |
| 1839 | using assms | |
| 1840 | proof (induction c rule: frag_induction) | |
| 1841 | case (diff a b) | |
| 1842 | then show ?case | |
| 1843 | by (metis (no_types, lifting) frag_extend_diff add_diff_eq diff_add_eq diff_add_eq_diff_diff_swap) | |
| 1844 | qed auto | |
| 1845 | qed | |
| 1846 | ||
| 1847 | hide_const (open) lookup single update keys range map map_key degree nth the_value items foldr mapp | |
| 1848 | ||
| 1849 | end |