section \ SI Units \ theory SI_Units imports Groups_mult HOL.Transcendental "HOL-Eisbach.Eisbach" begin named_theorems si_def and si_eq text\ The International System of Units (SI, abbreviated from the French Système international (d'unités)) is the modern form of the metric system and is the most widely used system of measurement. It comprises a coherent system of units of measurement built on seven base units, which are the second, metre, kilogram, ampere, kelvin, mole, candela, and a set of twenty prefixes to the unit names and unit symbols that may be used when specifying multiples and fractions of the units. The system also specifies names for 22 derived units, such as lumen and watt, for other common physical quantities. (cited from \<^url>\https://en.wikipedia.org/wiki/International_System_of_Units\).\ text\ This is an attempt to model the system and its derived entities (cf. \<^url>\https://www.quora.com/What-are-examples-of-SI-units\) in Isabelle/HOL. The design objective are twofold (and for the case of Isabelle somewhat contradictory, see below) The construction proceeds in three phases: \<^enum> We construct a generic type \<^theory_text>\Unit\ which is basically an "inner representation" or "semantic domain" of all SI types. Since SI-types have an interpretation in this domain, it serves to give semantics to type-constructors by operations on this domain, too. We construct a multiplicative group on it. \<^enum> From \<^theory_text>\Unit\ we build a \<^theory_text>\'a SI_tagged_domain\ types, i.e. a polymorphic family of values tagged with values from \<^theory_text>\Unit\. We construct multiplicative and additive groups over it. \<^enum> We construct a type-class characterizing SI - type expressions and types tagged with SI - type expressions; this construction paves the way to overloaded interpretation functions from SI type-expressions to \ section\The Domains of SI types and SI-tagged types\ subsection \ The \<^theory_text>\Unit\-type and its operations \ text \ An SI unit associates with each of the seven base unit an integer that denotes the power to which it is raised. We use a record to represent this 7-tuple, to enable code generation. \ record Unit = Meters :: int Kilograms :: int Seconds :: int Amperes :: int Kelvins :: int Moles :: int Candelas :: int text \ Units scaled by a power of 10 \ type_synonym SUnit = "int Unit_ext" abbreviation scale :: "SUnit \ int" where "scale \ more" text \ We define a commutative monoid for SI units. \ instantiation Unit_ext :: (one) one begin \ \ Here, $1$ is the dimensionless unit \ definition one_Unit_ext :: "'a Unit_ext" where [code_unfold, si_def]: "1 = \ Meters = 0, Kilograms = 0, Seconds = 0, Amperes = 0 , Kelvins = 0, Moles = 0, Candelas = 0, \ = 1 \" instance .. end instantiation Unit_ext :: (times) times begin \ \ Multiplication is defined by adding together the powers \ definition times_Unit_ext :: "'a Unit_ext \ 'a Unit_ext \ 'a Unit_ext" where [code_unfold, si_def]: "x * y = \ Meters = Meters x + Meters y, Kilograms = Kilograms x + Kilograms y , Seconds = Seconds x + Seconds y, Amperes = Amperes x + Amperes y , Kelvins = Kelvins x + Kelvins y, Moles = Moles x + Moles y , Candelas = Candelas x + Candelas y, \ = more x * more y \" instance .. end instance Unit_ext :: (comm_monoid_mult) comm_monoid_mult proof fix a b c :: "'a Unit_ext" show "a * b * c = a * (b * c)" by (simp add: times_Unit_ext_def mult.assoc) show "a * b = b * a" by (simp add: times_Unit_ext_def mult.commute) show "1 * a = a" by (simp add: times_Unit_ext_def one_Unit_ext_def) qed text \ We also define the inverse and division operations, and an abelian group. \ instantiation Unit_ext :: ("{times,inverse}") inverse begin definition inverse_Unit_ext :: "'a Unit_ext \ 'a Unit_ext" where [code_unfold, si_def]: "inverse x = \ Meters = - Meters x, Kilograms = - Kilograms x , Seconds = - Seconds x, Amperes = - Amperes x , Kelvins = - Kelvins x, Moles = - Moles x , Candelas = - Candelas x, \ = inverse (more x) \" definition divide_Unit_ext :: "'a Unit_ext \ 'a Unit_ext \ 'a Unit_ext" where [code_unfold]: "divide_Unit_ext x y = x * (inverse y)" instance .. end instance Unit_ext :: (ab_group_mult) ab_group_mult proof fix a b :: "'a Unit_ext" show "inverse a \ a = 1" by (simp add: inverse_Unit_ext_def times_Unit_ext_def one_Unit_ext_def) show "a \ inverse b = a div b" by (simp add: divide_Unit_ext_def) qed text \ It makes no sense to define a plus operator for SI units because we can only add together identical units, and this makes for a useless function. \ instantiation unit :: comm_monoid_add begin definition "zero_unit = ()" definition "plus_unit (x::unit) (y::unit) = ()" instance proof qed (simp_all) end instantiation unit :: comm_monoid_mult begin definition "one_unit = ()" definition "times_unit (x::unit) (y::unit) = ()" instance proof qed (simp_all) end instantiation unit :: inverse begin definition "inverse_unit (x::unit) = ()" definition "divide_unit (x::unit) (y::unit) = ()" instance .. end instance unit :: ab_group_mult by (intro_classes, simp_all) text \ A base unit is an SI_tagged_domain unit here precisely one unit has power 1. \ definition is_BaseUnit :: "Unit \ bool" where "is_BaseUnit u = (\ n. u = 1\Meters := n\ \ u = 1\Kilograms := n\ \ u = 1\Seconds := n\ \ u = 1\Amperes := n\ \ u = 1\Kelvins := n\ \ u = 1\Moles := n\ \ u = 1\Candelas := n\)" section\The Syntax and Semantics of SI types and SI-tagged types\ subsection \ Basic SI-types \ text \ We provide a syntax for type-expressions; The definition of the basic type constructors is straight-forward via a one-elementary set. \ typedef Length = "UNIV :: unit set" .. setup_lifting type_definition_Length typedef Mass = "UNIV :: unit set" .. setup_lifting type_definition_Mass typedef Time = "UNIV :: unit set" .. setup_lifting type_definition_Time typedef Current = "UNIV :: unit set" .. setup_lifting type_definition_Current typedef Temperature = "UNIV :: unit set" .. setup_lifting type_definition_Temperature typedef Amount = "UNIV :: unit set" .. setup_lifting type_definition_Amount typedef Intensity = "UNIV :: unit set" .. setup_lifting type_definition_Intensity typedef NoDimension = "UNIV :: unit set" .. setup_lifting type_definition_NoDimension type_synonym M = Mass type_synonym L = Length type_synonym T = Time type_synonym I = Current type_synonym \ = Temperature type_synonym N = Amount type_synonym J = Intensity type_notation NoDimension ("\") translations (type) "M" <= (type) "Mass" (type) "L" <= (type) "Length" (type) "T" <= (type) "Time" (type) "I" <= (type) "Current" (type) "\" <= (type) "Temperature" (type) "N" <= (type) "Amount" (type) "J" <= (type) "Intensity" subsection \ SI-type expressions and SI-type interpretation \ text \ The case for the construction of the multiplicative and inverse operators requires --- thus, the unary and binary operators on our SI type language --- require that their arguments are restricted to the set of SI-type expressions. The mechanism in Isabelle to characterize a certain sub-class of Isabelle-type expressions are \<^emph>\type classes\. We therefore need such a sub-class; for reasons of convenience, we combine its construction also with the "semantics" of SI types in terms of @{typ Unit}. \ subsubsection \ SI-type expression definition as type-class \ class si_type = finite + fixes si_sem :: "'a itself \ Unit" assumes unitary_unit_pres: "card (UNIV::'a set) = 1" syntax "_SI" :: "type \ logic" ("SI'(_')") translations "SI('a)" == "CONST si_sem TYPE('a)" text \ The sub-set of basic SI type expressions can be characterized by the following operation: \ class si_baseunit = si_type + assumes is_BaseUnit: "is_BaseUnit SI('a)" subsubsection \ SI base type constructors \ text\We embed the basic SI types into the SI type expressions: \ instantiation Length :: si_baseunit begin definition si_sem_Length :: "Length itself \ Unit" where "si_sem_Length x = 1\Meters := 1\" instance by (intro_classes, auto simp add: si_sem_Length_def is_BaseUnit_def, (transfer, simp)+) end instantiation Mass :: si_baseunit begin definition si_sem_Mass :: "Mass itself \ Unit" where "si_sem_Mass x = 1\Kilograms := 1\" instance by (intro_classes, auto simp add: si_sem_Mass_def is_BaseUnit_def, (transfer, simp)+) end instantiation Time :: si_baseunit begin definition si_sem_Time :: "Time itself \ Unit" where "si_sem_Time x = 1\Seconds := 1\" instance by (intro_classes, auto simp add: si_sem_Time_def is_BaseUnit_def, (transfer, simp)+) end instantiation Current :: si_baseunit begin definition si_sem_Current :: "Current itself \ Unit" where "si_sem_Current x = 1\Amperes := 1\" instance by (intro_classes, auto simp add: si_sem_Current_def is_BaseUnit_def, (transfer, simp)+) end instantiation Temperature :: si_baseunit begin definition si_sem_Temperature :: "Temperature itself \ Unit" where "si_sem_Temperature x = 1\Kelvins := 1\" instance by (intro_classes, auto simp add: si_sem_Temperature_def is_BaseUnit_def, (transfer, simp)+) end instantiation Amount :: si_baseunit begin definition si_sem_Amount :: "Amount itself \ Unit" where "si_sem_Amount x = 1\Moles := 1\" instance by (intro_classes, auto simp add: si_sem_Amount_def is_BaseUnit_def, (transfer, simp)+) end instantiation Intensity :: si_baseunit begin definition si_sem_Intensity :: "Intensity itself \ Unit" where "si_sem_Intensity x = 1\Candelas := 1\" instance by (intro_classes, auto simp add: si_sem_Intensity_def is_BaseUnit_def, (transfer, simp)+) end instantiation NoDimension :: si_type begin definition si_sem_NoDimension :: "NoDimension itself \ Unit" where "si_sem_NoDimension x = 1" instance by (intro_classes, auto simp add: si_sem_NoDimension_def is_BaseUnit_def, (transfer, simp)+) end lemma base_units [simp]: "is_BaseUnit SI(Length)" "is_BaseUnit SI(Mass)" "is_BaseUnit SI(Time)" "is_BaseUnit SI(Current)" "is_BaseUnit SI(Temperature)" "is_BaseUnit SI(Amount)" "is_BaseUnit SI(Intensity)" by (simp_all add: is_BaseUnit) subsubsection \ Higher SI Type Constructors: Inner Product and Inverse \ text\On the class of SI-types (in which we have already inserted the base SI types), the definitions of the type constructors for inner product and inverse is straight) forward.\ typedef ('a::si_type, 'b::si_type) UnitTimes (infixl "\" 69) = "UNIV :: unit set" .. setup_lifting type_definition_UnitTimes text \ We can prove that multiplication of two SI types yields an SI type. \ instantiation UnitTimes :: (si_type, si_type) si_type begin definition si_sem_UnitTimes :: "('a \ 'b) itself \ Unit" where "si_sem_UnitTimes x = SI('a) * SI('b)" instance by (intro_classes, simp_all add: si_sem_UnitTimes_def, (transfer, simp)+) end text \ Similarly, we define division of two SI types and prove that SI types are closed under this. \ typedef 'a UnitInv ("(_\<^sup>-\<^sup>1)" [999] 999) = "UNIV :: unit set" .. setup_lifting type_definition_UnitInv instantiation UnitInv :: (si_type) si_type begin definition si_sem_UnitInv :: "('a\<^sup>-\<^sup>1) itself \ Unit" where "si_sem_UnitInv x = inverse SI('a)" instance by (intro_classes, simp_all add: si_sem_UnitInv_def, (transfer, simp)+) end subsubsection \ Syntactic Support for SI type expressions. \ text\A number of type-synonyms allow for more compact notation: \ type_synonym ('a, 'b) UnitDiv = "'a \ ('b\<^sup>-\<^sup>1)" (infixl "'/" 69) type_synonym 'a UnitSquare = "'a \ 'a" ("(_)\<^sup>2" [999] 999) type_synonym 'a UnitCube = "'a \ 'a \ 'a" ("(_)\<^sup>3" [999] 999) type_synonym 'a UnitQuart = "'a \ 'a \ 'a \ 'a" ("(_)\<^sup>4" [999] 999) type_synonym 'a UnitInvSquare = "('a\<^sup>2)\<^sup>-\<^sup>1" ("(_)\<^sup>-\<^sup>2" [999] 999) type_synonym 'a UnitInvCube = "('a\<^sup>3)\<^sup>-\<^sup>1" ("(_)\<^sup>-\<^sup>3" [999] 999) type_synonym 'a UnitInvQuart = "('a\<^sup>4)\<^sup>-\<^sup>1" ("(_)\<^sup>-\<^sup>4" [999] 999) translations (type) "'a\<^sup>-\<^sup>2" <= (type) "('a\<^sup>2)\<^sup>-\<^sup>1" translations (type) "'a\<^sup>-\<^sup>3" <= (type) "('a\<^sup>3)\<^sup>-\<^sup>1" translations (type) "'a\<^sup>-\<^sup>4" <= (type) "('a\<^sup>4)\<^sup>-\<^sup>1" (* Need to add UnitQuart to the print translation *) print_translation \ [(@{type_syntax UnitTimes}, fn ctx => fn [a, b] => if (a = b) then Const (@{type_syntax UnitSquare}, dummyT) $ a else case a of Const (@{type_syntax UnitTimes}, _) $ a1 $ a2 => if (a1 = a2 andalso a2 = b) then Const (@{type_syntax UnitCube}, dummyT) $ a1 else case a1 of Const (@{type_syntax UnitTimes}, _) $ a11 $ a12 => if (a11 = a12 andalso a12 = a2 andalso a2 = b) then Const (@{type_syntax UnitQuart}, dummyT) $ a11 else raise Match | _ => raise Match)] \ subsection \ Derived Dimensions \ type_synonym Area = "L\<^sup>2" type_synonym Volume = "L\<^sup>3" type_synonym Acceleration = "L\T\<^sup>-\<^sup>1" type_synonym Frequency = "T\<^sup>-\<^sup>1" type_synonym Energy = "L\<^sup>2\M\T\<^sup>-\<^sup>2" type_synonym Power = "L\<^sup>2\M\T\<^sup>-\<^sup>3" type_synonym Force = "L\M\T\<^sup>-\<^sup>2" type_synonym Pressure = "L\<^sup>-\<^sup>1\M\T\<^sup>-\<^sup>2" type_synonym Charge = "I\T" type_synonym PotentialDifference = "L\<^sup>2\M\T\<^sup>-\<^sup>3\I\<^sup>-\<^sup>1" type_synonym Capacitance = "L\<^sup>-\<^sup>2\M\<^sup>-\<^sup>1\T\<^sup>4\I\<^sup>2" end