section \ SI Quantities \ theory SI_Quantities imports SI_Units Optics.Lenses begin subsection \ The \<^theory_text>\Quantity\-type and its operations \ record 'a Quantity = magn :: 'a \ \ Magnitude of the quantity \ unit :: Unit \ \ Unit of the quantity \ lemma Quantity_eq_intro: assumes "magn x = magn y" "unit x = unit y" "more x = more y" shows "x = y" by (simp add: assms) instantiation Quantity_ext :: (times, times) times begin definition [si_def]: "times_Quantity_ext x y = \ magn = magn x \ magn y, unit = unit x \ unit y, \ = more x \ more y \" instance .. end lemma magn_times [simp]: "magn (x \ y) = magn x \ magn y" by (simp add: times_Quantity_ext_def) lemma unit_times [simp]: "unit (x \ y) = unit x \ unit y" by (simp add: times_Quantity_ext_def) lemma more_times [simp]: "more (x \ y) = more x \ more y" by (simp add: times_Quantity_ext_def) instantiation Quantity_ext :: (zero, zero) zero begin definition "zero_Quantity_ext = \ magn = 0, unit = 1, \ = 0 \" instance .. end lemma magn_zero [simp]: "magn 0 = 0" by (simp add: zero_Quantity_ext_def) lemma unit_zero [simp]: "unit 0 = 1" by (simp add: zero_Quantity_ext_def) lemma more_zero [simp]: "more 0 = 0" by (simp add: zero_Quantity_ext_def) instantiation Quantity_ext :: (one, one) one begin definition [si_def]: "one_Quantity_ext = \ magn = 1, unit = 1, \ = 1 \" instance .. end lemma magn_one [simp]: "magn 1 = 1" by (simp add: one_Quantity_ext_def) lemma unit_one [simp]: "unit 1 = 1" by (simp add: one_Quantity_ext_def) lemma more_one [simp]: "more 1 = 1" by (simp add: one_Quantity_ext_def) instantiation Quantity_ext :: (inverse, inverse) inverse begin definition [si_def]: "inverse_Quantity_ext x = \ magn = inverse (magn x), unit = inverse (unit x), \ = inverse (more x) \" definition [si_def]: "divide_Quantity_ext x y = \ magn = magn x / magn y, unit = unit x / unit y, \ = more x / more y \" instance .. end lemma magn_inverse [simp]: "magn (inverse x) = inverse (magn x)" by (simp add: inverse_Quantity_ext_def) lemma unit_inverse [simp]: "unit (inverse x) = inverse (unit x)" by (simp add: inverse_Quantity_ext_def) lemma more_inverse [simp]: "more (inverse x) = inverse (more x)" by (simp add: inverse_Quantity_ext_def) lemma magn_divide [simp]: "magn (x / y) = magn x / magn y" by (simp add: divide_Quantity_ext_def) lemma unit_divide [simp]: "unit (x / y) = unit x / unit y" by (simp add: divide_Quantity_ext_def) lemma more_divide [simp]: "more (x / y) = more x / more y" by (simp add: divide_Quantity_ext_def) instance Quantity_ext :: (comm_monoid_mult, comm_monoid_mult) comm_monoid_mult by (intro_classes, simp_all add: one_Quantity_ext_def times_Quantity_ext_def mult.assoc, simp add: mult.commute) instance Quantity_ext :: (ab_group_mult, ab_group_mult) ab_group_mult by (intro_classes, rule Quantity_eq_intro, simp_all) subsection \ SI Tagged Types \ text\We 'lift' SI type expressions to SI tagged type expressions as follows:\ typedef (overloaded) ('n, 'u::si_type) tQuant ("_[_]" [999,0] 999) = "{x :: 'n Quantity. unit x = SI('u)}" morphisms fromUnit toUnit by (rule_tac x="\ magn = undefined, unit = SI('u) \" in exI, simp) setup_lifting type_definition_tQuant text \ Coerce values when their units are equivalent \ definition coerceUnit :: "'u\<^sub>2 itself \ 'a['u\<^sub>1::si_type] \ 'a['u\<^sub>2::si_type]" where "SI('u\<^sub>1) = SI('u\<^sub>2) \ coerceUnit t x = (toUnit (fromUnit x))" section\Operations SI-tagged types via their Semantic Domains\ subsection\Predicates on SI-tagged types\ text \ Two SI types are equivalent if they have the same value-level units. \ lift_definition Quant_equiv :: "'n['a::si_type] \ 'n['b::si_type] \ bool" (infix "\\<^sub>Q" 50) is "(=)" . text\This gives us an equivalence, but, unfortunately, not a congruence.\ lemma Quant_equiv_refl [simp]: "a \\<^sub>Q a" by (simp add: Quant_equiv_def) lemma Quant_equiv_sym: "a \\<^sub>Q b \ b \\<^sub>Q a" by (simp add: Quant_equiv_def) lemma Quant_equiv_trans: "\ a \\<^sub>Q b; b \\<^sub>Q c \ \ a \\<^sub>Q c" by (simp add: Quant_equiv_def) (* the following series of equivalent statements ... *) lemma coerceQuant_eq_iff: fixes x :: "'a['u\<^sub>1::si_type]" assumes "SI('u\<^sub>1) = SI('u\<^sub>2::si_type)" shows "(coerceUnit TYPE('u\<^sub>2) x) \\<^sub>Q x" by (metis Quant_equiv.rep_eq assms coerceUnit_def toUnit_cases toUnit_inverse) (* or equivalently *) lemma coerceQuant_eq_iff2: fixes x :: "'a['u\<^sub>1::si_type]" assumes "SI('u\<^sub>1) = SI('u\<^sub>2::si_type)" and "y = (coerceUnit TYPE('u\<^sub>2) x)" shows "x \\<^sub>Q y" using Quant_equiv_sym assms(1) assms(2) coerceQuant_eq_iff by blast lemma updown_eq_iff: fixes x :: "'a['u\<^sub>1::si_type]" fixes y :: "'a['u\<^sub>2::si_type]" assumes "SI('u\<^sub>1) = SI('u\<^sub>2::si_type)" and "y = (toUnit (fromUnit x))" shows "x \\<^sub>Q y" by (simp add: assms(1) assms(2) coerceQuant_eq_iff2 coerceUnit_def) text\This is more general that \y = x \ x \\<^sub>Q y\, since x and y may have different type.\ find_theorems "(toUnit (fromUnit _))" lemma eq_ : fixes x :: "'a['u\<^sub>1::si_type]" fixes y :: "'a['u\<^sub>2::si_type]" assumes "x \\<^sub>Q y" shows "SI('u\<^sub>1) = SI('u\<^sub>2::si_type)" by (metis (full_types) Quant_equiv.rep_eq assms fromUnit mem_Collect_eq) subsection\Operations on SI-tagged types\ lift_definition Quant_times :: "('n::times)['a::si_type] \ 'n['b::si_type] \ 'n['a \'b]" (infixl "\<^bold>\" 69) is "(*)" by (simp add: si_sem_UnitTimes_def times_Quantity_ext_def) lift_definition Quant_inverse :: "('n::inverse)['a::si_type] \ 'n['a\<^sup>-\<^sup>1]" ("(_\<^sup>-\<^sup>\)" [999] 999) is "inverse" by (simp add: inverse_Quantity_ext_def si_sem_UnitInv_def) abbreviation Quant_divide :: "('n::{times,inverse})['a::si_type] \ 'n['b::si_type] \ 'n['a/'b]" (infixl "\<^bold>'/" 70) where "Quant_divide x y \ x \<^bold>\ y\<^sup>-\<^sup>\" abbreviation Quant_sq ("(_)\<^sup>\" [999] 999) where "u\<^sup>\ \ u\<^bold>\u" abbreviation Quant_cube ("(_)\<^sup>\" [999] 999) where "u\<^sup>\ \ u\<^bold>\u\<^bold>\u" abbreviation Quant_quart ("(_)\<^sup>\" [999] 999) where "u\<^sup>\ \ u\<^bold>\u\<^bold>\u\<^bold>\u" abbreviation Quant_neq_sq ("(_)\<^sup>-\<^sup>\" [999] 999) where "u\<^sup>-\<^sup>\ \ (u\<^sup>\)\<^sup>-\<^sup>\" abbreviation Quant_neq_cube ("(_)\<^sup>-\<^sup>\" [999] 999) where "u\<^sup>-\<^sup>\ \ (u\<^sup>\)\<^sup>-\<^sup>\" abbreviation Quant_neq_quart ("(_)\<^sup>-\<^sup>\" [999] 999) where "u\<^sup>-\<^sup>\ \ (u\<^sup>\)\<^sup>-\<^sup>\" instantiation tQuant :: (zero,si_type) zero begin lift_definition zero_tQuant :: "('a, 'b) tQuant" is "\ magn = 0, unit = SI('b) \" by simp instance .. end instantiation tQuant :: (one,si_type) one begin lift_definition one_tQuant :: "('a, 'b) tQuant" is "\ magn = 1, unit = SI('b) \" by simp instance .. end instantiation tQuant :: (plus,si_type) plus begin lift_definition plus_tQuant :: "'a['b] \ 'a['b] \ 'a['b]" is "\ x y. \ magn = magn x + magn y, unit = SI('b) \" by (simp) instance .. end instance tQuant :: (semigroup_add,si_type) semigroup_add by (intro_classes, transfer, simp add: add.assoc) instance tQuant :: (ab_semigroup_add,si_type) ab_semigroup_add by (intro_classes, transfer, simp add: add.commute) instance tQuant :: (monoid_add,si_type) monoid_add by (intro_classes; (transfer, simp)) instance tQuant :: (comm_monoid_add,si_type) comm_monoid_add by (intro_classes; transfer, simp) instantiation tQuant :: (uminus,si_type) uminus begin lift_definition uminus_tQuant :: "'a['b] \ 'a['b]" is "\ x. \ magn = - magn x, unit = unit x \" by (simp) instance .. end instantiation tQuant :: (minus,si_type) minus begin lift_definition minus_tQuant :: "'a['b] \ 'a['b] \ 'a['b]" is "\ x y. \ magn = magn x - magn y, unit = unit x \" by (simp) instance .. end instance tQuant :: (numeral,si_type) numeral .. instance tQuant :: (ab_group_add,si_type) ab_group_add by (intro_classes, (transfer, simp)+) instantiation tQuant :: (times,si_type) times begin lift_definition times_tQuant :: "'a['b] \ 'a['b] \ 'a['b]" is "\ x y. \ magn = magn x * magn y, unit = SI('b) \" by simp instance .. end instance tQuant :: (power,si_type) power .. instance tQuant :: (semigroup_mult,si_type) semigroup_mult by (intro_classes, transfer, simp add: mult.assoc) instance tQuant :: (ab_semigroup_mult,si_type) ab_semigroup_mult by (intro_classes, (transfer, simp add: mult.commute)) instance tQuant :: (semiring,si_type) semiring by (intro_classes, (transfer, simp add: distrib_left distrib_right)+) instance tQuant :: (semiring_0,si_type) semiring_0 by (intro_classes, (transfer, simp)+) instance tQuant :: (comm_semiring,si_type) comm_semiring by (intro_classes, transfer, simp add: linordered_field_class.sign_simps(18) mult.commute) instance tQuant :: (mult_zero,si_type) mult_zero by (intro_classes, (transfer, simp)+) instance tQuant :: (comm_semiring_0,si_type) comm_semiring_0 by (intro_classes, (transfer, simp)+) instantiation tQuant :: (real_vector,si_type) real_vector begin lift_definition scaleR_tQuant :: "real \ 'a['b] \ 'a['b]" is "\ r x. \ magn = r *\<^sub>R magn x, unit = unit x \" by simp instance by (intro_classes, (transfer, simp add: scaleR_add_left scaleR_add_right)+) end instance tQuant :: (ring,si_type) ring by (intro_classes, (transfer, simp)+) instance tQuant :: (comm_monoid_mult,si_type) comm_monoid_mult by (intro_classes, (transfer, simp add: mult.commute)+) instance tQuant :: (comm_semiring_1,si_type) comm_semiring_1 by (intro_classes; (transfer, simp add: semiring_normalization_rules(1-8,24))) instantiation tQuant :: (divide,si_type) divide begin lift_definition divide_tQuant :: "'a['b] \ 'a['b] \ 'a['b]" is "\ x y. \ magn = magn x div magn y, unit = SI('b) \" by simp instance .. end instantiation tQuant :: (inverse,si_type) inverse begin lift_definition inverse_tQuant :: "'a['b] \ 'a['b]" is "\ x. \ magn = inverse (magn x), unit = SI('b) \" by simp instance .. end instantiation tQuant :: (order,si_type) order begin lift_definition less_eq_tQuant :: "'a['b] \ 'a['b] \ bool" is "\ x y. magn x \ magn y" . lift_definition less_tQuant :: "'a['b] \ 'a['b] \ bool" is "\ x y. magn x < magn y" . instance by (intro_classes, (transfer, simp add: less_le_not_le)+) end lift_definition mk_unit :: "'a \ 'u itself \ ('a::one)['u::si_type]" is "\ n u. \ magn = n, unit = SI('u) \" by simp syntax "_mk_unit" :: "logic \ type \ logic" ("UNIT'(_, _')") translations "UNIT(n, 'a)" == "CONST mk_unit n TYPE('a)" subsection \Polymorphic Operations for Elementary SI Units \ definition [si_def]: "meter = UNIT(1, Length)" definition [si_def]: "second = UNIT(1, Time)" definition [si_def]: "kilogram = UNIT(1, Mass)" definition [si_def]: "ampere = UNIT(1, Current)" definition [si_def]: "kelvin = UNIT(1, Temperature)" definition [si_def]: "mole = UNIT(1, Amount)" definition [si_def]: "candela = UNIT(1, Intensity)" subsubsection \The Projection: Stripping the SI-Tags \ definition magnQuant :: "'a['u::si_type] \ 'a" ("\_\\<^sub>Q") where "magnQuant x = magn (fromUnit x)" subsubsection \More Operations \ lemma unit_eq_iff_magn_eq: "x = y \ \x\\<^sub>Q = \y\\<^sub>Q" by (auto simp add: magnQuant_def, transfer, simp) lemma unit_equiv_iff: fixes x :: "'a['u\<^sub>1::si_type]" and y :: "'a['u\<^sub>2::si_type]" shows "x \\<^sub>Q y \ \x\\<^sub>Q = \y\\<^sub>Q \ SI('u\<^sub>1) = SI('u\<^sub>2)" proof - have "\t ta. (ta::'a['u\<^sub>2]) = t \ magn (fromUnit ta) \ magn (fromUnit t)" by (simp add: magnQuant_def unit_eq_iff_magn_eq) then show ?thesis by (metis (full_types) Quant_equiv.rep_eq coerceQuant_eq_iff2 eq_ magnQuant_def) qed lemma unit_le_iff_magn_le: "x \ y \ \x\\<^sub>Q \ \y\\<^sub>Q" by (auto simp add: magnQuant_def; (transfer, simp)) lemma magnQuant_zero [si_def]: "\0\\<^sub>Q = 0" by (simp add: magnQuant_def, transfer, simp) lemma magnQuant_one [si_def]: "\1\\<^sub>Q = 1" by (simp add: magnQuant_def, transfer, simp) lemma magnQuant_plus [si_def]: "\x + y\\<^sub>Q = \x\\<^sub>Q + \y\\<^sub>Q" by (simp add: magnQuant_def, transfer, simp) lemma magnQuant_times [si_def]: "\x * y\\<^sub>Q = \x\\<^sub>Q * \y\\<^sub>Q" by (simp add: magnQuant_def, transfer, simp) lemma magnQuant_div [si_def]: "\x / y\\<^sub>Q = \x\\<^sub>Q / \y\\<^sub>Q" by (simp add: magnQuant_def, transfer, simp) lemma magnQuant_qinv [si_def]: "\x\<^sup>-\<^sup>\\\<^sub>Q = inverse \x\\<^sub>Q" by (simp add: magnQuant_def, transfer, simp) lemma magnQuant_qdiv [si_def]: "\(x::('a::field)[_]) \<^bold>/ y\\<^sub>Q = \x\\<^sub>Q / \y\\<^sub>Q" by (simp add: magnQuant_def, transfer, simp add: field_class.field_divide_inverse) lemma magnQuant_numeral [si_def]: "\numeral n\\<^sub>Q = numeral n" apply (induct n, simp_all add: si_def) apply (metis magnQuant_plus numeral_code(2)) apply (metis magnQuant_one magnQuant_plus numeral_code(3)) done lemma magnQuant_mk [si_def]: "\UNIT(n, 'u::si_type)\\<^sub>Q = n" by (simp add: magnQuant_def, transfer, simp) method si_calc = (simp add: unit_eq_iff_magn_eq unit_le_iff_magn_le si_def) end