Meta-Languages and Semantics for Equation-Based Modeling and Simulation David Broman

Meta-Languages and Semantics for Equation-Based Modeling and Simulation David Broman
Linköping Studies in Science and Technology
Thesis No. 1333
Meta-Languages and Semantics for
Equation-Based Modeling and
Simulation
by
David Broman
Department of Computer and Information Science
Linköpings universitet
SE-581 83 Linköping, Sweden
Linköping 2010
ii
Copyright notice for Chapter 2 and 6:
© ACM, 2006. This is the author's version of the work. It is posted here by permission of ACM for your
personal use. Not for redistribution. The definitive version was published in Proceedings of the 5th
international conference on Generative programming and component engineering, Portland, Oregon,
USA , 2006, http://doi.acm.org/10.1145/1173706.1173729
ACM COPYRIGHT NOTICE. Copyright © 2006 by the Association for Computing Machinery, Inc.
Permission to make digital or hard copies of part or all of this work for personal or classroom use is
granted without fee provided that copies are not made or distributed for profit or commercial advantage
and that copies bear this notice and the full citation on the first page. Copyrights for components of this
work owned by others than ACM must be honored. Abstracting with credit is permitted. To copy
otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission
and/or a fee. Request permissions from Publications Dept., ACM, Inc., fax +1 (212) 869-0481, or
[email protected]
Cover page: The first equation with equality sign, by Robert Recorde, 1557 [60].
Watercolor interpretation of the equation by David Broman, 2010.
ISBN 978-91-7393-335-3
ISSN 0345-7524
Thesis No. 1333
October 1, 2010
Electronic version available at:
http://urn.kb.se/resolve?urn=urn:nbn:se:liu:diva-58743
Printed by LiU-Tryck, Linköping 2010
Abstract
Performing computational experiments on mathematical models instead of building and
testing physical prototypes can drastically reduce the develop cost for complex systems
such as automobiles, aircraft, and powerplants. In the past three decades, a new category
of equation-based modeling languages has appeared that is based on acausal and objectoriented modeling principles, enabling good reuse of models. However, the modeling
languages within this category have grown to be large and complex, where the specifications of the language’s semantics are informally defined, typically described in natural
languages. The lack of a formal semantics makes these languages hard to interpret unambiguously and to reason about. This thesis concerns the problem of designing the semantics of such equation-based modeling languages in a way that allows formal reasoning
and increased correctness. The work is presented in two parts.
In the first part we study the state-of-the-art modeling language Modelica. We analyze
the concepts of types in Modelica and conclude that there are two kinds of type concepts:
class types and object types. Moreover, a concept called structural constraint delta is
proposed, which is used for isolating the faults of an over- or under-determined model.
In the second part, we introduce a new research language called the Modeling Kernel
Language (MKL). By introducing the concept of higher-order acausal models (HOAMs),
we show that it is possible to create expressive modeling libraries in a manner analogous
to Modelica, but using a small and simple language concept. In contrast to the current
state-of-the-art modeling languages, the semantics of how to use the models, including
meta operations on models, are also specified in MKL libraries. This enables extensible
formal executable specifications where important language features are expressed through
libraries rather than by adding completely new language constructs. MKL is a statically
typed language based on a typed lambda calculus. We define the core of the language
formally using operational semantics and prove type safety. An MKL interpreter is implemented and verified in comparison with a Modelica environment.
This research work has been funded by CUGS (the National Graduate School in Computer Science, Sweden), by SSF under the VISIMOD II project, by Vinnova under the
NETPROG Safe and Secure Modeling and Simulation on the GRID project, by the ITEA2
OPENPROD project, by Linköping University under the ELLIIT project, and by the
Swedish Research Council (VR).
Department of Computer and Information Science
Linköpings universitet
SE-581 83 Linköping, Sweden
To my lovely wife Åsa and wonderful childen Tove and Hampus
Acknowledgments
First, I would like to express my gratitude to my supervisor Peter Fritzson, who made
this thesis possible in the first place by believing in me and enrolling me into the PhD
program. You have supported and helped me in many situations during this thesis work.
My greatest thanks to Jeremy Siek who was my host when I was visiting University
of Colorado at Boulder as a guest scholar in 2008 and then became my co-supervisor.
Your help, energy, and friendliness have been invaluable for me while struggling with
semantics, lemmas, and proofs.
I would especially like to thank Thomas Schön, my old friend and research "mentor",
for giving me inspiration and advice during this thesis work.
Thanks to all the members of Modelica Association who have taken part in the Modelica design meetings that I have been attending. These discussions have given many ideas
to this research. I would also like to thank all colleagues at PELAB for interesting, fun,
and sometimes devastating long coffee break discussions. A special thanks goes to Bodil
Mattson Kihlström for all your help during these years.
These five years have not just included time for research, but also a large amount of
teaching. I would especially like to thank Kristian Sandahl who has been my colleague regarding common teaching efforts in software engineering. Our interesting and sometimes
too long discussions have been giving a lot of energy during these years.
During most of the time of this thesis work, I have been living in Stockholm but
working in Linköping. Several people have helped me to make this life easier. Thanks to
Thomas Sjöland and Björn Lisper for arranging a room at KTH in Kista, Mikael Zayenz
Lagerkvist for interesting discussions, and my grandmother Ingrid Broman who has been
an almost too friendly host in Linköping.
I would also like to thank the following people for many interesting discussions during the last years: Johan Åkesson, Sébastien Furic, Dirk Zimmer, Hans Olsson, Thomas
Doumenc, and Michael Tiller. I would especially like to thank Henrik Nilsson for all
rewarding discussions and for inviting me over to Nottingham.
Parts of the final draft of this thesis have been proofread by Jeremy Siek, Thomas
Schön, Henrik Nilsson, Walid Taha, Sibylle Schupp, and Hilding Elmqvist. I’m grateful
for all comments and suggestions which substantially have improved this work. I would
especially like to thank Peter Fritzson for his painstaking effort of reading the whole draft.
Thanks to all my friends and family for all the support you have given me. Thanks
to my mother Eva, father Olof, mother-in-law Britt-Marie, and father-in-law Rune for all
invaluable help you have given me and my family during the last months. Especially, I
would like to express my deepest gratitude to my lovely wife Åsa, who has encouraged
me during this time. Without your help, love, and energy, this thesis would never have
been completed. I also want to thank my wonderful children Tove and Hampus. During
my parental leaves in the fall 2008 and the fall 2010 you have really reminded me that
there are other more important things in life than modeling languages.
Finally, I would like to thank the Ethiopian goatherd who according to a legend first
discovered coffee. Without this vital beverage, this thesis would never have been finished.
Linköping, August 30, 2010
David Broman
vii
Contents
1 Introduction
1.1 Modeling and Simulation . . . . . . . . . . . . . . . . . . . . .
1.1.1 Example of a Mechanical System . . . . . . . . . . . .
1.1.2 Importance of Modeling and Simulation . . . . . . . . .
1.2 Equation-Based Object-Oriented Languages . . . . . . . . . . .
1.2.1 Domain-Specific Language . . . . . . . . . . . . . . . .
1.2.2 Objects . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.3 Mathematical Equations and Acausality . . . . . . . . .
1.3 Problem Area . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3.1 Safety Aspects . . . . . . . . . . . . . . . . . . . . . .
1.3.2 Expressiveness and Extensibility Aspects . . . . . . . .
1.4 Research Questions . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1 Understanding the Semantics of the Modelica Language
1.4.2 Early Detection of Modeling Errors . . . . . . . . . . .
1.4.3 Expressive and Extensible Formal Semantics . . . . . .
1.4.4 Scope . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.5 Thesis Outline and Contributions . . . . . . . . . . . . . . . . .
1.5.1 Part I - The Modelica Language . . . . . . . . . . . . .
1.5.2 Part II - The Modeling Kernel Language . . . . . . . . .
1.5.3 Part III - Related Work and Concluding Remarks . . . .
1.5.4 Published Papers . . . . . . . . . . . . . . . . . . . . .
1.5.5 Origin of Contributions . . . . . . . . . . . . . . . . . .
1.5.6 Reading Guidelines . . . . . . . . . . . . . . . . . . . .
1.6 Research Method . . . . . . . . . . . . . . . . . . . . . . . . .
ix
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
2
3
6
6
7
8
9
12
12
14
14
15
15
15
16
16
16
17
18
18
20
21
21
x
Contents
I
The Modelica Language
23
2
Introduction to Modelica
2.1 Equation-Based Modeling in Modelica . . . . . . . . . . . . . . . . . . .
2.2 The Modelica Compilation and Simulation Process . . . . . . . . . . . .
2.3 Chapter Summary and Conclusions . . . . . . . . . . . . . . . . . . . . .
25
26
29
31
3
Specifying the Modelica Language
3.1 Introduction and Motivation . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1 Unambiguous and Understandable Language Specification . . . .
3.1.2 Previous Specification Attempts . . . . . . . . . . . . . . . . . .
3.1.3 Abstract Syntax as a Middle-Way Strategy . . . . . . . . . . . .
3.2 Specifying the Modelica Language . . . . . . . . . . . . . . . . . . . . .
3.2.1 Transformation Aspects - What is Actually the Result of an Execution? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.2 Checking Aspects - What is actually a Valid Modelica Model? . .
3.2.3 Specification Approaches - How can we State What it’s all About?
3.3 An Abstract Syntax Specification Approach . . . . . . . . . . . . . . . .
3.3.1 Specifying the Elaboration Process . . . . . . . . . . . . . . . .
3.3.2 Specifying the Abstract Syntax . . . . . . . . . . . . . . . . . . .
3.3.3 The Structure of an Abstract Syntax . . . . . . . . . . . . . . . .
3.3.4 A Connector S-AST Example with Meta-Variables . . . . . . . .
3.4 Chapter Summary and Conclusions . . . . . . . . . . . . . . . . . . . . .
33
34
34
34
35
36
Growing the Modelica Language
4.1 Different Ways of Growing a Language . . . . . . . . . . . . . . . . . .
4.1.1 The Ways of Growth Matrix . . . . . . . . . . . . . . . . . . . .
4.1.2 Growth by Adding New Language Features . . . . . . . . . . . .
4.1.3 Growth by Adding Syntactic Sugar . . . . . . . . . . . . . . . .
4.1.4 Growth by New Meanings of Annotations or Built-in Functions .
4.1.5 Growth by New User Defined Abstractions . . . . . . . . . . . .
4.1.6 Restricting the Language . . . . . . . . . . . . . . . . . . . . . .
4.2 The Right Way to Grow . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1 Stakeholders of an Object-Oriented Equation-Based Modeling Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.2 Language Designers’ Perspective . . . . . . . . . . . . . . . . .
4.2.3 End Users’ Perspective . . . . . . . . . . . . . . . . . . . . . . .
4.2.4 Library Users’ Perspective . . . . . . . . . . . . . . . . . . . . .
4.2.5 Tool Vendors’ Perspective . . . . . . . . . . . . . . . . . . . . .
4.3 Chapter Summary and Conclusions . . . . . . . . . . . . . . . . . . . . .
45
46
46
46
47
49
50
50
51
Types in the Modelica Language
5.1 Types, Subtyping and Inheritance . . . . . . .
5.1.1 Language Safety and Type Systems .
5.1.2 Subtyping . . . . . . . . . . . . . . .
5.1.3 Inheritance . . . . . . . . . . . . . .
5.1.4 Structural and Nominal Type Systems
55
56
56
58
59
61
4
5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
36
37
39
40
40
41
42
42
44
51
51
52
52
53
53
xi
5.2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
63
64
65
65
67
67
71
74
74
6 Over- and Under-Constrained Systems of Equations
6.1 Problem and Motivation . . . . . . . . . . . . . . . . . . . . . .
6.2 Featherweight Modelica . . . . . . . . . . . . . . . . . . . . . .
6.2.1 Syntax and Semantics . . . . . . . . . . . . . . . . . . .
6.2.2 Type-Equivalence and Subtyping . . . . . . . . . . . . .
6.3 The Approach of Structural Constraint Delta . . . . . . . . . . . .
6.3.1 Algorithms for Computing C∆ and E∆ . . . . . . . . . .
6.3.2 Extending the Type System with C∆ . . . . . . . . . . . .
6.4 Prototype Implementation . . . . . . . . . . . . . . . . . . . . .
6.4.1 Constraint Checking of Separately Compiled Components
6.4.2 Error Detection and Debugging . . . . . . . . . . . . . .
6.5 Chapter Summary and Conclusions . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
75
76
77
78
78
80
81
87
87
88
90
91
5.3
5.4
Polymorphism . . . . . . . . . . . . . . .
5.2.1 Subtype Polymorphism . . . . . .
5.2.2 Parametric Polymorphism . . . .
5.2.3 Ad-hoc Polymorphism . . . . . .
Modelica Types . . . . . . . . . . . . . .
5.3.1 Class Types and Object Types . .
5.3.2 Prefixes in Types . . . . . . . . .
5.3.3 Completeness of the Type Syntax
Chapter Summary and Conclusions . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
II The Modeling Kernel Language
7 Introduction to Functional Programming in MKL
7.1 Functional Programming in MKL . . . . . . . . .
7.1.1 Higher-Order Functions and Currying . . .
7.1.2 Tuples, Lists, and Pattern Matching . . . .
7.1.3 Equality, Abstract Data Types, and Modules
7.2 Lambda Calculus and Operational Semantics . . .
7.2.1 Untyped Lambda Calculus . . . . . . . . .
7.3 Chapter Summary and Conclusions . . . . . . . . .
93
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
95
96
97
101
103
105
105
108
8 Modeling in MKL
8.1 Basic Physical Modeling in MKL . . . . . . . . . . . . . . . .
8.1.1 A Simple Electrical Circuit . . . . . . . . . . . . . . . .
8.1.2 Models and Equation Systems . . . . . . . . . . . . . .
8.2 Higher-Order Acausal Modeling . . . . . . . . . . . . . . . . .
8.2.1 Parameterization of Models with Models . . . . . . . .
8.2.2 Recursively Defined Models . . . . . . . . . . . . . . .
8.2.3 Higher-Order Functions for Generic Model Composition
8.3 Dynamic Data Structures and Polymorphism . . . . . . . . . . .
8.3.1 Model Composition over Lists of Models . . . . . . . .
8.3.2 Parametric Polymorphism . . . . . . . . . . . . . . . .
8.4 Chapter Summary and Conclusions . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
109
110
111
113
115
116
117
119
121
121
122
123
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
xii
9
Contents
Intensional Analysis of Models
9.1 Models and Unknowns . . . . . . . . .
9.1.1 Unknowns . . . . . . . . . . .
9.1.2 Model Type . . . . . . . . . . .
9.1.3 Models as Data Structures . . .
9.2 Intensional Analysis of Models . . . . .
9.2.1 Pattern Matching on Models . .
9.2.2 Analyzing Systems of Equations
9.3 Chapter Summary and Conclusions . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
125
126
126
126
128
129
129
131
135
10 Semantics of MKL
10.1 Syntax . . . . . . . . . . . . . . . . . . . .
10.2 Type System and Model Lifting . . . . . .
10.2.1 Type Consistency . . . . . . . . . .
10.2.2 Type System . . . . . . . . . . . .
10.2.3 Model Lifting . . . . . . . . . . . .
10.3 Cast Insertion and Dynamic Semantics . . .
10.3.1 Cast Insertion . . . . . . . . . . . .
10.3.2 Dynamic Semantics . . . . . . . .
10.3.3 Casts . . . . . . . . . . . . . . . .
10.4 Type Safety . . . . . . . . . . . . . . . . .
10.5 Extending the Core . . . . . . . . . . . . .
10.5.1 Other Expressions and the Bot Type
10.5.2 Pattern Matching . . . . . . . . . .
10.5.3 Lifting and Binary Operators . . . .
10.5.4 Equality . . . . . . . . . . . . . . .
10.6 Chapter Summary and Conclusions . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
137
137
139
140
141
143
144
145
146
148
148
151
151
152
152
152
153
11 Elaboration Semantics
11.1 Overview of Elaboration . . . . . . . . . . . . . .
11.1.1 Type Checking of Models . . . . . . . . .
11.1.2 Collapsing the Instance Hierarchy . . . . .
11.2 Connection Semantics . . . . . . . . . . . . . . .
11.2.1 A Minimal Circuit in Modelica . . . . . .
11.2.2 A Minimal Circuit in MKL . . . . . . . . .
11.2.3 Formalization of the Connection Semantics
11.2.4 Composition, and Multiple States . . . . .
11.2.5 Executable Specification . . . . . . . . . .
11.3 Extracting Model Information . . . . . . . . . . .
11.3.1 Hierarchy Naming vs. Probing . . . . . . .
11.3.2 Modeling with Probes in MKL . . . . . . .
11.3.3 Elaboration Semantics of Probes . . . . . .
11.4 Chapter Summary and Conclusions . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
159
159
160
161
161
161
164
168
170
173
177
177
178
180
181
.
.
.
.
.
.
.
.
xiii
12 Implementation, Verification, and Evaluation
12.1 Implementation . . . . . . . . . . . . . . . . . .
12.1.1 File Includer and Symbol Table . . . . .
12.1.2 Desugaring . . . . . . . . . . . . . . . .
12.1.3 Type Checking and Model Translation . .
12.1.4 Program Evaluation after Translation . .
12.2 Uses of Models . . . . . . . . . . . . . . . . . .
12.2.1 Exporting the DAE to Flat Modelica . . .
12.2.2 Simulating the DAE . . . . . . . . . . .
12.3 Verification . . . . . . . . . . . . . . . . . . . .
12.4 Discussion and Evaluation . . . . . . . . . . . .
12.4.1 Safety Aspects . . . . . . . . . . . . . .
12.4.2 Expressiveness and Extensibility Aspects
12.4.3 Performance Aspects . . . . . . . . . . .
12.5 Chapter Summary and Conclusions . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
III Related Work and Concluding Remarks
13 Related Work
13.1 Equation-Based Modeling Languages . . . . . . . . . . .
13.1.1 Modelica and Predecessors . . . . . . . . . . . . .
13.1.2 Extensions to Modelica . . . . . . . . . . . . . . .
13.1.3 VHDL-AMS . . . . . . . . . . . . . . . . . . . .
13.1.4 Verilog-AMS . . . . . . . . . . . . . . . . . . . .
13.1.5 gPROMS . . . . . . . . . . . . . . . . . . . . . .
13.1.6 Hybrid Chi . . . . . . . . . . . . . . . . . . . . .
13.1.7 Functional Hybrid Modeling and Hydra . . . . . .
13.1.8 Sol . . . . . . . . . . . . . . . . . . . . . . . . .
13.1.9 Acumen . . . . . . . . . . . . . . . . . . . . . . .
13.1.10 Comparison to MKL . . . . . . . . . . . . . . . .
13.2 Modelica Semantics . . . . . . . . . . . . . . . . . . . . .
13.2.1 Natural Semantics . . . . . . . . . . . . . . . . .
13.2.2 Instance Creation . . . . . . . . . . . . . . . . . .
13.2.3 Modelica Types . . . . . . . . . . . . . . . . . . .
13.2.4 Balanced Models . . . . . . . . . . . . . . . . . .
13.2.5 Structural Checking of Models . . . . . . . . . . .
13.3 MKL Semantics . . . . . . . . . . . . . . . . . . . . . . .
13.3.1 Formal Semantics . . . . . . . . . . . . . . . . . .
13.3.2 Metaprogramming in EOO Context . . . . . . . .
13.3.3 Metaprogramming in General Purpose Languages .
183
183
184
184
185
185
186
186
187
189
191
191
193
195
196
199
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
201
201
201
202
202
203
203
203
204
204
205
205
205
205
206
206
206
207
207
207
208
209
14 Concluding Remarks
211
14.1 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
14.1.1 Understanding the Semantics of the Modelica Language . . . . . 212
14.1.2 Early Detection of Modeling Errors . . . . . . . . . . . . . . . . 212
xiv
Contents
14.1.3 Expressive and Extensible Formal Semantics . . . . . .
14.2 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.2.1 Extensional Metaprogramming . . . . . . . . . . . . . .
14.2.2 Hybrid and Structural Dynamic Systems . . . . . . . . .
14.2.3 Code Generation and Time Aspects . . . . . . . . . . .
14.2.4 Structural Constraint Delta . . . . . . . . . . . . . . . .
14.2.5 Polymorphism, Type Classes, and Algebraic Data Types
14.2.6 Efficient Compilation . . . . . . . . . . . . . . . . . . .
14.2.7 More Complex Modeling . . . . . . . . . . . . . . . . .
14.2.8 Uses Beyond Simulation . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
213
214
214
214
215
215
216
216
216
216
A Syntax of MKL
A.1 Concrete Syntax . . . . . . . . .
A.1.1 Notational Conventions .
A.1.2 Comments . . . . . . .
A.1.3 Lexical Structure . . . .
A.1.4 Reserved Words . . . .
A.1.5 Top-Level . . . . . . . .
A.1.6 Types . . . . . . . . . .
A.1.7 Expressions . . . . . . .
A.1.8 Pattern Matching . . . .
A.2 Abstract Syntax . . . . . . . . .
A.2.1 Types . . . . . . . . . .
A.2.2 Expressions . . . . . . .
A.2.3 Values . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
217
217
217
217
217
218
218
218
219
220
221
222
223
223
B Built-in Abstract Data Types
B.1 Array . . . . . . . . . .
B.2 Set . . . . . . . . . . . .
B.3 Map . . . . . . . . . . .
B.4 DAESolver . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
225
225
226
226
228
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
C Big-step Semantics of MKL Core
D MKL Library
D.1 Base . . . . . . . . . . . . . .
D.2 Modeling . . . . . . . . . . .
D.3 Electrical . . . . . . . . . . .
D.4 AnalogElectrical . . . . . . .
D.5 Mechanical . . . . . . . . . .
D.6 RotationalMechanical . . . . .
D.7 Elaboration . . . . . . . . . .
D.8 MechatronicElaboration . . .
D.9 Simulation . . . . . . . . . . .
D.10 Export Modelica . . . . . . .
D.11 Performance Test Source Code
D.11.1 MechSys . . . . . . .
229
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
231
232
233
233
233
234
235
236
239
239
241
243
243
xv
D.11.2 CircuitHierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Bibliography
247
Index
260
xvi
Contents
1
Introduction
thesis concerns the problem of designing and defining the semantics of equationbased modeling languages. Such languages, used for mathematical modeling of
the dynamics of complex physical systems (e.g., automobiles, aircraft, and powerplants),
have in the previous decade gained considerable attention from both industry and academia.
This language category is based on the concepts of object-orientation and acausal modeling using equations. This enables good reuse of model components resulting in considerably reduced modeling effort [48]. One such language is Modelica [104], which
is an attempt to unify concepts and notation from several earlier languages originating
from research projects and industrial initiatives, as well as developing a new language
design to address modeling problems. Other examples of languages in this category are
gPROMS [13, 115] for chemical engineering and VHDL-AMS [40, 72] a hardware description language (HDL) with analog and mixed-signal extensions.
However, these languages are large and very complex, where the concrete syntax is
formally defined using grammars, but the semantics informally described using natural
language. The lack of formal semantics makes these languages hard to interpret unambiguously and precisely reason about. A major challenge regarding designing such a
complex modeling language is to find a good trade-off between language safety (i.e., protect model abstractions by detecting and isolating errors and faults), performance (e.g.,
fast model simulation), expressiveness (i.e., ease of expressing complex models and/or
tasks), and extensibility (i.e., mechanisms to add new language features). The topic of
this thesis is the problem of designing and defining language semantics with respect to
some of the trade-offs mentioned above.
The rest of the introduction chapter is organized as follows:
T
HIS
• We first give the background of mathematical modeling and simulation together
with an overview of how equation-based object-oriented (EOO) languages fit into
the picture of domain-specific languages (DSLs) (Section 1.1 and 1.2).
1
2
1 Introduction
• We discuss the problem area (Section 1.3) and state the research questions. (Section 1.4).
• We present an outline of this thesis together with a summary of the main contributions of the work. We list publications that are part of this thesis and describe the
origin of the contributions (Section 1.5).
• Finally, we discuss our scientific viewpoint of the work and the research method
used (Section 1.6).
1.1
Modeling and Simulation
Modeling is today a very active area of research in computer science as well as in most
disciplines of engineering. The term model is used in various settings meaning completely different things, which may unfortunately lead to confusion and misunderstanding
regarding the subject. During the recent decades, modeling of software has become very
popular; especially in industry. One of the main driving forces is the Model Driven Architecture (MDA) [96] initiative and the popular graphical modeling framework of the
Unified Modeling Language (UML) [113, 114].
This thesis does not concern modeling or languages used for modeling of software
or software systems. Instead, we are primarily interested in languages in which physical
systems can be described using models. In particular, we are concerned with languages
that can support modeling within in a combination of different physical domains, e.g.,
electrical, mechanical, and hydraulic domains.
To be able to reason about the process of modeling and simulation, some definitions
of terms have to be clarified. The following definition was first coined by Marvin Minsky
in 1965 [35, p. 5]:
“A model (M) for a system (S) and an experiment (E) is anything to which E
can be applied in order to answer a question about S”
According to this definition, a model can be seen as an abstraction of the system, where
some details of the real system is left out. The definition does not imply that the model
has to be of a certain kind (e.g., a mathematical formula or computer program), only
that experiments should be possible to apply to it to answer questions about the system.
However, in this thesis the term model means a mathematical model describing dynamic
and static properties of a continuous-time system, i.e., a system evolving continuously
as a function of time. Several modeling languages also address discrete-time modeling,
which however is not covered by this thesis and left as future work.
Many physical systems can be described by ordinary differential equations (ODEs)
of the form
F t, x, ẋ, u) = 0,
(1.1)
ẋ = f t, x, u),
(1.2)
or in explicit state-space form
3
1.1 Modeling and Simulation
Figure 1.1: A simple model of a rotational mechanical system representing a drive
shaft with a torque.
where x ∈ Rn is the unknown state vector to be solved for, u ∈ Rm the vector of input
signals, and t the independent variable representing time.
An ODE has a general solution, but when studying a model for a specific application
it is desirable to find a unique solution by also giving the initial conditions . The ODE
together with the initial conditions is an initial value problem :
ẋ = f t, x, u)
x(t0 ) = x0
(1.3)
(1.4)
where x0 ∈ Rn is the initial conditions. Note that the dimensions of the vectors x0 and x
are equal.
1.1.1 Example of a Mechanical System
Let us consider a simplified example of a drive shaft for a truck, i.e., the part of a powertrain used for transmitting the rotational torque between axles. A graphical model of the
shaft is outlined in Figure 1.1 and an example where such a shaft could be used in reality
is illustrated in Figure 1.2. The model represents two inertias connected in series, with a
spring in between. To the left, a torque is driving the shaft.
Because the inertial bodies are rigid, the angle ϕ (rad) is the same on each side of
the body, here defined as ϕ1 and ϕ2 . However, the torque τ (N m) is different between
each component. For example τ2 is affected both by the driving torque to the left and the
conserved energy in the spring.
We define the angular velocities ω1 (rad/s) and ω2 together with the equations ω1 =
ϕ˙1 and ω2 = ϕ˙2 . By using Newton’s law of motion in the rotational domain, we know
that the angular acceleration ω̇ (rad/s2 ) is proportional to the torque of the shaft, where
the proportionality constant is the inertia J (N m/s2 ). Hence, we have the equations
J1 · ω̇1 = τ1 + τ2 and J2 · ω̇2 = τ3 + τ4 respectively. Because the right hand side of the
shaft is not connected, we have τ4 = 0. The torque affected by the spring is proportional
to the angular difference ϕ2 −ϕ1 , where the proportional constant c (N m/rad) is called the
spring constant. This adds the equation τ2 = c · (ϕ2 − ϕ1 ) to the system of equations. We
also know that the spring torque is the same on each side of the spring, but with different
sign, i.e., τ2 = −τ3 . Finally, we also have the input torque u giving u = τ1 .
We now have a system of equations with 8 equations and 8 unknowns (ϕ1 , ϕ2 , ω1 ,
ω2 , τ1 , τ2 , τ3 , τ4 ), where four unknowns appears differentiated (ϕ̇1 , ϕ̇2 , ω̇1 , ω̇2 ).
4
1 Introduction
Figure 1.2: The figure shows Tandem axles RST 2370 A B-Ride Bogie (Volvo
Trucks). The shaft between the axles is an example of a rotating shaft that is part
of a powertrain for transmission of the torque. Used with permission.
We can rewrite our example as follows:
ϕ̇1
ϕ̇2
=
=
ω̇1
=
ω̇2
=
τ1
=
ω1
ω2
τ1 + τ2
J1
τ3 + τ4
J2
u
τ2
τ3
=
=
c · (ϕ2 − ϕ1 )
−c · (ϕ2 − ϕ1 )
(1.10)
(1.11)
τ4
=
0
(1.12)
(1.5)
(1.6)
(1.7)
(1.8)
(1.9)
Here the last four equations (1.9-1.12) are called algebraic equations.
Recall the definition of an ODE (1.1) where all variables except the independent variable appears differentiated. In the mechanical example above, variables τ1 , τ2 , τ3 , τ4
do not appear differentiated. These variables are called algebraic meaning that they are
free from derivatives. Hence, our system of equations is not an ODE, but a system of
5
1.1 Modeling and Simulation
3.5
3
ω2 (rad/s)
2.5
2
1.5
1
0.5
0
0
5
10
time (s)
15
20
Figure 1.3: Plot of the angular velocity ω2 of the shaft example.
differential algebraic equations (DAE) . The general form of a DAE is
F (t, x, ẋ, y, u) = 0,
(1.13)
where t is the independent variable of time, x a vector of variables that appear differentiated, y a vector of algebraic variables, and u a vector of input signals.
In this simple example, the algebraic equations can be directly eliminated by substitution into equations (1.7) and (1.8), thus forming an ODE. However, this is not possible in
the general case and there are sophisticated methods described in the literature for solving DAEs numerically and symbolically [83, 118]. Differential-algebraic equations is the
kind of equation system used in equation-based languages discussed in this thesis, such
as Modelica, for describing continuous-time behavior.
We have in this example shown how we describe a mathematical model of a mechanical system. We can now use our model to answer questions about the system, using
experiments. This can be performed using simulation, or as stated by Granino Korn and
John Wait according to Cellier [35, p. 6],
“A simulation is an experiment performed on a model”
Hence, we can simulate our example model to study the behavior of the physical system.
Assuming that we know the parameters of the system (J1 , J2 , and c) and that we
have a known input signal u, we can simulate the system using a numerical integration
algorithm to solve the system of differential equations1 .
Figure 1.3 shows an example where the angular velocity ω2 has been be plotted for
the interval 0 to 20 s. The plot shows how the shaft starts to oscillate due to flexibility
introduced by the spring.
1 In the example, we assign J = 10 kg m2 , J = 2 kg m2 and c = 5 N m/rad. We also let the input signal
1
2
u be a constant value of 2 N m. These values do not represent a shaft for a powertrain in reality; it is used for
the purpose of showing a clear oscillation.
6
1 Introduction
1.1.2 Importance of Modeling and Simulation
Why is modeling and simulation of physical systems important? Before we discuss this
question, let us define the process of modeling by quoting Cellier and Kofman [37, p. 8]:
“The process of modeling concerns itself with the extraction of knowledge
from the physical plant to be simulated, organizing that knowledge appropriately, and representing it in some unambiguous fashion.”
Modeling and simulation is perhaps one of the most common techniques for answering
questions by scientists and engineers. While scientists are focused on understanding and
observing the world, engineers primarily want to design new artifacts. In both cases
modeling is a central process for abstracting, extracting, and organizing the knowledge
for further analysis.
There are many reasons why modeling and simulation is beneficial. For example:
• It is typically much cheaper to perform experiments on the model compared to
performing them directly on the real system. For example, when developing a
control system for a landing gear of an aircraft, several engineers can test their
control system simultaneously by simulating a model of the landing gear, instead
of using direct access of a physical prototype.
• It might be too dangerous to do the experiments in reality. When testing “whatif” scenarios on a nuclear power-plant, it is safer to do these experiments on a
mathematical model compared to a real plant.
• The system may not exist, i.e., the model is a prototype that is evaluated and tested
during development. Most product development cycles still need physical prototypes for evaluation, but by using a combination of virtual prototypes of mathematical models the development time can potentially be dramatically shortened.
• Some unknown variables are not accessible in the real system, but can be observed
in a simulation. For example, measuring the temperature inside certain areas of an
engine can be physically impossible without affecting the engine’s behavior.
• It is easy to use and modify models, to change parameters and perform new experiments (simulations). For example, it is much easier to experiment with and change
the size of wind turbines on a model than on physical prototypes.
However, as pointed out both by Cellier [35] and Fritzson [51], the ease of use is also
the main danger and drawback with modeling and simulation. There is a risk to ignore
the fact that the model is only valid under certain conditions, and that the model is in fact
an abstraction of the reality and not the reality itself. Consequently, care must be taken
regarding which simulations are suitable to apply on a model, so that the results reach the
desired level of accuracy.
1.2
Equation-Based Object-Oriented Languages
In the previous section we gave an introduction to continuous-time system modeling and
simulation. Designing languages for continuous-time systems is not new and one of the
1.2 Equation-Based Object-Oriented Languages
7
earliest initiatives was the Continuous System Simulation Language (CSSL) specified
in 1967 [11]. Derivations of CSSL are all based on state-space descriptions where the
underlying mathematical description is an ODE [35]. General-purpose simulation tools,
e.g., Simulink [92], using block diagrams and causal connections, have now dominated
the area for many years. Block diagrams make it possible to graphically model ODEs and
the software tool is then used for performing the numerical simulation.
In the 1960’s, the first object-oriented language was designed with the initial purpose
of discrete event-based modeling and simulation. This language, Simula [44], founded
the fundamental concepts of object-orientation and object-oriented languages. The fundamental principles of object-oriented modeling languages for continuous-time modeling
and simulation have been around for about 30 years. According to Cellier [36], this started
with the pioneering work explored in two separate PhD theses by Hilding Elmqvist [47]
and Tom Runge.
Several languages have been developed during the years with the common properties
of physical modeling using equation systems. Today the state of the art within multidomain physical modeling (e.g., containing mechanical, electrical, hydraulic, thermal,
fluid, and control components) is Modelica [104]. Other examples of languages with
similar modeling and simulation capabilities are gPROMS [13, 115] for chemical engineering and VHDL-AMS [40, 72] a hardware description language (HDL) with analog
and mixed-signal extensions.
However, not until recently has a common name for this category of languages appeared. We call this language category equation-based object-oriented (EOO) languages 2 .
The exact meaning of this name can be a subject for discussion, but we propose the following definition:
Definition 1.2.1 (Equation-based object-oriented (EOO) language).
An equation-based object-oriented (EOO) language is a domain-specific language used
for modeling the interaction between objects, by utilizing mathematical equations to provide an acausal description of behavior.
This informal definition includes the following vague terms:
• Domain-specific language
• Objects
• Mathematical equations and acausality
In the rest of this section, we will discuss and clarify these terms.
1.2.1 Domain-Specific Language
A domain-specific language (DSL) can, according to van Deursen et. al. [148, p. 26], be
defined as follows:
“A domain-specific language (DSL) is a programming language or executable
specification language that offers, through appropriate notations and abstractions, expressive power focused on, and usually restricted to, a particular
problem domain.”
2 The term was coined by the author of this thesis and first publicly used at a poster session at the conference
on programing language design and implementation (PLDI) in 2006 [22].
8
1 Introduction
The vague defining term of this definition is the term problem domain. In [148], van
Deursen et. al. implicitly defined the term by giving examples of existing DSLs within
areas such as software engineering, systems software, multi-media, telecommunication,
and miscellaneous domains such as simulation, robot control and solving partial differential equations. Other authors, such as Czarnecki and Eisenecker [43, p. 34], define this as
follows:
“Domain: An area of knowledge
• Scoped to maximize the satisfaction of the requirements of its stakeholders
• Includes a set of concepts and terminology understood by practioners
in the area
• Includes the knowledge of how to build software systems (or parts of
software systems) in that area”
From this point of view, we can for example regard both Modelica, gPROMS, and VHDLAMS as domain-specific languages, with their expressive power focused on modeling of
physical systems. However, according to van Deursen et. al. [148], DSLs are usually
small languages with a restricted set of notations and abstractions. In fact, DSLs are
sometimes referred to as little languages [147], compared to larger general-purpose languages (GPLs) . Can we regard Modelica with an informal language specification of 250
pages [104] as a small language? Moreover, Modelica is commonly referred to as a multidomain modeling language. How can this be regarded as a domain-specific language?
As with all informal definitions, it depends on the interpretation of the terms - in
this case the word domain. We regard for example Modelica and VHDL-AMS as large
domain-specific languages with regards to the domain of modeling physical systems. This
holds especially when comparing to a GPL, in which arbitrary computational tasks can be
described. Moreover, we may also regard particular libraries defined in these languages
as specialized sub-domain-specific languages, e.g., the Modelica Bond Graph library [38]
or the Fluid library [105]. With this view, the Modelica design group that is designing the
language are the domain experts of physical modeling and the designers of a particular
library the sub-domain experts for a particular physical domain.
1.2.2 Objects
The term object-oriented in EOO is not used with exactly the same meaning as for the
common object-oriented programming (OOP) languages. In for example Smalltalk [64]
an object is an instance of class that can send or receive messages. In C++ [75, 139], behavior is described by invoking methods associated with an object. Somewhat simplified,
we might say that an object in OOP can be described be the following equation
objectOOP = data + methods
Similar to OOP languages, objects in EOO languages are used for describing the combination of data and behavior. In contrast to OOP, the behavior of the objects in EOO
languages is described by mathematical equations instead of methods or message passing. Hence, one view of an object in EOO would be
1.2 Equation-Based Object-Oriented Languages
9
objectEOO = data + equations
Many EOO languages, such as Modelica and Omola [6] use language mechanisms from
OOP languages (for example inheritance and subtyping-polymorphism), but we do not
regard this as a necessary condition for being an EOO language. There are many concepts
related to OOP languages and as shown by Armstrong [7] there is no clear consensus of
what actually defines the core concepts of OO languages.
Recall Figure 1.1 showing a graphical Modelica model of a rotational mechanical
system. Objects are in Modelica referred to as components . This mechanical model has
four components (objects): a torque, two inertias, and a spring. We say that objects are
instances of EOO models (or Modelica models ). Moreover, an EOO model can compose
and encapsulate one or more model instances. For example, the objects inertia1 and
inertia2 are instances of a common EOO model representing the general behavior of
an inertia. When the objects are created, they are given different inertia values, J1 and J2
respectively.
Objects are connected via ports (called connectors in Modelica). In Figure 1.1, the
object intertia1 is connected to torque and spring. The object intertia2 is
connected to the spring on its left hand side and is unconnected on the right hand side.
In state-of-the-art EOO languages, objects are used only for hierarchically compose
EOO models, i.e., objects are not created dynamically during simulation. However, this
is an active area of research called structurally dynamic systems [62, 155].
We shall note one thing regarding terminology. As stated in the beginning of Section 1.1, we use the term model with the general meaning of a mathematical model, i.e.,
a system of equations. When it is clear from the context, the term model may either refer
to an EOO model or the underlying equation system represented by the EOO model.
1.2.3 Mathematical Equations and Acausality
The foundation of EOO languages is that behavior is described declaratively using mathematical equations. Even though most EOO languages describe behavior using DAEs
(e.g., Modelica and VHDL-AMS), the behavior could also be described by partial differential equations (PDEs) or by equational constraints for model-based diagnosis [30].
The main point is that the equations are acausal (also called non-causal), meaning that
the causality of how to solve the equations is not decided at modeling time. Acausality
should be present at two levels of abstraction:
• at the equation-level
• at the object connection level
We say that a system of equations is acausal, if the order in which the unknowns are
solved is not decided at modeling time. Consider for example the equation of Ohm’s law
v = R · i,
10
1 Introduction
(a)
1
s
J1
10
Divide 1
Constant 2
1
s
omega1
phi1
Integrator 1
Integrator 3
5
tau2
Gain
tau1
1
s
2
phi2
Constant 1
Integrator 2
-5
Gain 1
2
1
s
J2
Constant
Divide
omega2
omega2
Integrator
Scope
tau3
(b)
Figure 1.4: Model (a) is a causal block diagram model of the mechanical system in
Figure 1.1. Model (b) shows how the model in Figure 1.1 has been reused and the
original spring replaced with a parallel spring-damper.
where v is the voltage, R the resistance, and i the current. Depending on which variable
is unknown, it can be translated into three different assignment statements
v := R · i,
i := v/R,
R := v/i,
Acausality at the object connection level is the second central part of acausality of EOO
languages. Recall the mechanical system in Section 1.1.1, where we used the graphical
model as illustration for the rotational system when performing the equational modeling
by hand. However, Figure 1.1 is actually the graphical representation of an executable
Modelica model. One of the main benefits with an acausal model such as this one is that
the topology corresponds to how objects in the physical world would be connected. This
is referred to as physical modeling [51]. A causal model of the same mechanical system is
given in Figure 1.4a. The causal model consists of blocks with defined input and output.
Compared to the acausal model, the physical topology is lost.
Now, assume that we reuse the model in Figure 1.1 and replaces the spring object with
a spring-damper object. The resulting model is shown in Figure 1.4b. Because the model
11
1.2 Equation-Based Object-Oriented Languages
is acausal, a simulation tool can automatically generate an new equation system for the
updated model. However, if the block model is changed to include a spring-damper, the
large parts of the diagram needs to be rearranged, because the block diagram is dependent
on the causality of the underlying equation system.
The key to acausal physical models is in the basic physical principle of conservation
of energy , stating that the total amount of energy in a closed system is constant over time;
it can neither be created nor destroyed. To support this principle, acausal ports have both
a potential variable (also called across ) and a flow variable (also called through ). This
principle of potential/flow variables is applicable in several different physical domains,
e.g., [104]:
Domain
Electrical Analog
Translational Mechanics 1D
Rotational Mechanics 1D
Heat Transfer
Magnetic
Potential Variables
Electrical Potential
Distance
Angle
Temperature
Magnetic Potential
Flow Variables
Electrical Current
Force
Torque
Heat Flow Rate
Magnetic Flux
If two or more ports are connected, the potential variables are set equal, whereas the
flow variables are summed-to-zero. In the electrical domain the sum-to-zero principle
corresponds to Kirchhoff’s current law. For example, consider the connections between
the spring, the damper, and the inertia2 object in Figure 1.4b. The following
equality equations are generated for the potential variables:
ϕs2 = ϕ2
ϕd2 = ϕ2
Note that no redundant equation is generated between ϕs2 and ϕd2 . Finally, the sum-tozero equation is generated:
τs2 + τd2 + τ3 = 0
The phase of generating equations from the description of connections between ports is
referred to as connection semantics . This phase is in turn part of the elaboration process 3 , where an EOO model is translated into a set of equations. The other two essential
phases in this elaboration process are type checking (deciding which models that are considered correct according to a defined type system) and collapsing the instance hierarchy
(translating components into a system of equations).
The generated equations from the elaboration process forms the resulting DAE of the
EOO model. The process of a general translation from a DAE to an ODE (or to a so called
index-1 DAE) is the result of extensive research and involves symbolic manipulation of
3 In this thesis, we call the process elaboration. In the Modelica specification 3.2, this process is called flattening because it creates a flat system of equations. Sometimes, this translation is also referred to as instantiation.
However, we think that both these terms are misleading. The former, because the final equation system does
not need to be flat - it can still be represented in a hierarchical structure. The latter, because it is typically performed at compile time and is not allocating memory analogous to instance creating in standard programming
languages.
12
1 Introduction
the equation system. Key aspects of this process are the use of Pantelides algorithm [118],
block lower triangular form (BLT) [70, 71], dummy-derivatives [94], and tearing [49].
The details of this translation falls outside the scope of this thesis, but are central to the
performance and accuracy of implementations of Modelica software tools.
1.3
Problem Area
This thesis concerns the problem of designing and defining the semantics of equationbased modeling languages. By semantics we mean the meaning of a model. This includes
both the static semantics (translating an EOO model into an equation system and rejecting
illegal models) and dynamic semantics (to use the equation system, i.e., for numerical
simulation). A major challenge regarding the design of such complex languages is to find
a good trade-off between different quality and design aspects of the language. In this
section we give an overview of the problem area with regards to the following aspects:
• Safety aspects - to protect model abstractions by detecting and isolating errors and
faults.
• Expressiveness and extensibility aspects - makeing it easy to express complex modeling tasks and to provide mechanisms for extending the language with new features.
1.3.1 Safety Aspects
It is not always possible to simulate an EOO model because the model might have been
incorrectly specified. Furthermore, even if a simulation result is generated, this does
not imply that the result is correct, i.e., that the simulation result corresponds to the real
system. We will in the first section outline the overall problems and challenges regarding
safety aspects of EOO languages and their environments,
By following the terminology defined in the IEEE Standard 100 [107], we define an
error to be something that is made by human beings. As the consequence of an error, a
fault exists in an artifact, such as an EOO model, source code, or a language specification.
Another word for fault would be bug or defect. If a fault is executed, this results in a
failure , i.e., it is possible to detect that something went wrong.
People make mistakes, i.e., make errors when modeling systems. This can result in
either incorrect simulation results, or no results at all. To produce products (e.g., aircraft,
cars, and factory machines) based on incorrect simulation results, can be very expensive
or even result in devastating consequences. Hence, it is of great importance to efficiently
handle errors in a safe manner.
There are many different sources of errors in a modeling and simulation environment.
Consider Figure 1.5, which outlines relations between sources of errors and faults. The
center box illustrates the simulation tool, which takes an EOO model as input (left side)
and produces a simulation result if the simulation was successful, or a simulation failure
report if an error occurs during simulation. In the model, there are three actors that can
produce errors that affect the tool’s output.
1.3 Problem Area
13
Figure 1.5: Relations between possible errors and faults in a modeling and simulation environment.
System Modeling Errors. A system modeling error can result in an EOO model containing an EOO model fault, which obviously affects the simulation result. Some
modeling errors can result in failures already in the elaboration phase (e.g., illegal
access of elements in objects or wrong number of equations), while others result in
simulation failures during simulation (e.g., numerical singularities). Moreover, an
engineer can make mistakes while modeling a system, which still gives simulation
results, but perhaps incorrect values. In this thesis, we are mainly concerned with
modeling errors that can result in a failure during the elaboration phase, i.e., before
simulation.
Language Design and Specification Errors. Almost all commonly used languages
evolve over time, resulting in high demands on the language design effort and the
work to produce precise, consistent, and error free language specifications. The
Modelica language is no exception, which has resulted in a large and complex language with an informal specification using plain text. This fact can lead to language
design errors because it is hard to grasp the complete semantics of the language.
For example, it could be a fault in the specification of the type system if models
containing faults can be executed, although they should have been rejected by the
type checker. Moreover, if the language design effort intends to give guarantees
that a certain kind of modeling error should be detected, it is obviously necessary
that the specification is precise and easy to reason about. Hence, one of the main
challenges is to be able to define this kind of languages in a precise way, using
formal semantics.
Tool Implementation Errors. In addition, language specification faults and unclear semantics may lead to tool implementation errors. If only one tool exists for the
language, the importance of implementation errors compared to the specification
might be ignorable. However, if there exist several tools, tool implementation errors may lead to incompatible models or even non-deterministic simulation results.
For example, Modelica has a complex semantics for name lookup that has in our experience lead to considerable effort to make the OpenModelica [53, 117] compiler
compatible with other commercial tools of Modelica, primarily Dymola [45].
To mitigate the fact that people make errors, we see three major challenges regarding error
handling:
14
1 Introduction
1. Detecting the existence of an error early. If a simulation fails, it is trivial to detect
that an error must exist. However, if a simulation takes 48 hours to complete, it is
not desirable to wait 46 hours before the error is detected.
2. Isolating the fault implied by the error. If we have detected that an error must
exist, how do we know where the actual fault is located? Is it located in the main
model, in some model library, or even in the simulation tool itself? For example,
if an engine is modeled and then translated into a system of equations containing
20000 equations and 20001 unknowns, it is trivial to detect that this is a fault.
However, it is a non-trivial task to isolate the fault so that the error can be resolved.
3. Guaranteeing that faults do not exist. If we can detect an error by using e.g.,
testing and then isolate the fault using some kind of debugging technique, how
do we know that there do not exist any other errors? Consequently, would it be
possible to give guarantees that some kind of fault cannot exist in a model, e.g.,
that a specific type of errors will always be detected?
1.3.2 Expressiveness and Extensibility Aspects
State of the art EOO languages, such as Modelica, are expressive regarding the ability
to define new models within existing libraries. However, new libraries of the Modelica
standard library (MSL) are often released together with a new version of the Modelica
language that supports new language constructs required for the new library. Examples
include the handling of over-determined connectors used in the multi-body library and
stream connectors for the Fluid library. This leads to a continuously growing the size
and complexity of the language. The challenge is to make the EOO language expressive enough so that the language does not need to be extended when a new libraries are
released.
Software tools and compilers can use the EOO models for different purposes. One
such purpose, which today is the most common use, is to analyze the equation system,
transform it, generate executable code, and simulate the system. However, there are several other potential uses of mathematical models, such as optimization problems [79],
model reduction, generation of real-time simulation code, and exporting data to standardized model formats [34]. The problem is that an EOO language has to be extended with
additional language constructs to support the new use, leading to either a number of new
languages with specific extensions, or to an EOO language that is even larger and more
complex. Hence, the challenge is to make the EOO language extensible so that the language does not have to be updated if a model is used in a new manner.
1.4
Research Questions
From the description of the problem area in Section 1.3, a number of research questions
are formulated below. We categorize the questions within three areas:
• Understanding the Semantics of the Modelica Language
• Early Detection of Modeling Errors
• Expressive and Extensible Formal Semantics
1.4 Research Questions
15
1.4.1 Understanding the Semantics of the Modelica Language
Both the dynamic and static semantics of the Modelica language are informally described
using natural language and source code examples. Because the language has grown to be
very large and complex, it is hard in the short term to define a formal semantics for the
complete language; leading to the following question:
Research Question 1. How can an informal language specification be restructured to be
less ambiguous and still understandable?
A common way of statically detecting and isolating errors in a language is to use type
checking. However, in Modelica, the concept of types is only implicitly described using
informal natural language. Hence, our second question in the study concerns Modelica
types.
Research Question 2. What is the actual meaning of types in Modelica and how does
this compare to the class concept in the language?
1.4.2 Early Detection of Modeling Errors
If a model is incorrectly described and contains more equations than unknowns (overdetermined) or fewer equations than unknown (under-determined), it is easy to detect the
error after elaboration by just counting the number of equations and variables. However,
it is much harder to isolate the error to a specific model instance. Earlier approaches have
tried to analyze the flat system of equations after elaboration, and then tracing back the
faults to the original models [29], leading to the following question:
Research Question 3. Is it possible to define an approach to detect under- and overconstrained errors in the model before elaboration, enabling the user to isolate the fault
to a certain model instance?
1.4.3 Expressive and Extensible Formal Semantics
State of the art EOO languages are large and complex with the semantics informally
described. Programming language researchers have for decades formalized languages
based on small and expressive calculi, where the lambda calculus [12] is the prominent
one.
Research Question 4. Is it possible to formally define an EOO language as an extension of a typed lambda calculus that gives the expressive power of state of the art EOO
languages?
As described in the problem area description in Section 1.3, a major problem for language
extensibility is that new modeling demands often require changes in the language specification of the EOO language. This requires both new language revisions and that different
vendors need to update their modeling and simulation products. This process is both time
consuming and error prone and limits the possibility for the domain experts to express
their modeling needs.
16
1 Introduction
Research Question 5. Can we design a modeling kernel language where domain experts
can extend both modeling constructs for an EOO language, as well as the semantics for
using the models?
1.4.4 Scope
The research questions stated in the previous sections are broad and therefore the following scope is given for the thesis:
• For domain experts of EOO languages who are developing libraries, the concrete
syntax is of essential importance. However, in this thesis we do not make any
attempt of analyzing how or which syntax is most convenient for domain experts.
• EOO languages typically have both a textual and a graphical representation. Even
though we acknowledge the need and benefits of graphical syntax, we are only
analyzing the textual representation in this thesis.
• Performance aspects of the proposed solution are only analyzed at a high level of
abstraction because our prototype is implemented as an interpreter and not as a
compiler.
• We investigate the formal semantics of expressing models, for elaborating structured models down to equation systems, and for analyzing the equation system.
The semantics for the model compiler backend concerning symbolic manipulation
and solving the DAEs are outside the scope of the thesis.
• We are primarily concerned with the continuous-time aspects of EOO languages
and we will not discuss hybrid models (the mixture of continuous-time and discretetime models) in this thesis.
• We will not attempt to formally define an existing EOO language, e.g., Modelica.
1.5
Thesis Outline and Contributions
The thesis is divided into two main parts. Part I relates to the Modelica language and in
Part II we propose a new research language called the Modeling Kernel Language (MKL) .
In the following, we give an overview of the contents of the thesis as well as a statement of the main contributions. For each of the contributions, a note is given for where
the contribution is discussed and detailed, as well as a pointer to which research question
the contribution relates to.
1.5.1 Part I - The Modelica Language
Part I is dedicated to studying the Modelica language - both with regards to interpreting
and understanding the current semantics of the language, as well as proposing extensions
and improvements to the language. In Part I we make the following main contributions:
1.5 Thesis Outline and Contributions
17
• We discuss different strategies for specifying the Modelica language as well as
suggesting approaches that make it easier to extend and grow the language in the
future. This work does not present any specific technical contribution, but instead
presents a categorization and discussion about the Modelica specification (Chapters
3 and 4, Research Question 1).
• We give to the best of our knowledge, the first description and interpretation of the
type concept in Modelica to the level of precision that makes it clear that Modelica
has two categories of types: class types and object types. The corresponding paper
was published in 2006 [27] and has influenced the improved description of the
Modelica specification (Chapter 5, Research Question 2).
• We propose an approach for determining if a model is under- or over-constrained
without elaborating its subcomponents. The main insight is the idea of annotating the constraint value on types. We call the approach structural constraint delta,
denoted C∆ , and define an algorithm for a subset of the Modelica language. However, this approach is not limited to Modelica and should be useful in other EOO
languages as well. The work was published in 2006 [28] and somewhat influenced
the design of balanced models, part of the Modelica 3.0 standard from 2007 (Chapter 6, Research Question 3).
1.5.2 Part II - The Modeling Kernel Language
Part II concerns the problem of creating a formally defined language that is both expressive and extensible (Research Question 5 and 4).
The proposed research language MKL is not intended as a new end-user EOO language. It is a kernel language in which domain experts and language designers can define
EOO language constructs within MKL libraries. Also, the main objective is not to translate available EOO languages to MKL. Instead, we see MKL as a research language for
exploring new language constructs and principles, which can then later perhaps find their
way into available EOO languages.
In Part II we make the following specific contributions:
• We explore the concept that we call higher-order acausal models (HOAMs), which
is the combination of higher-order functions and acausal models. We show that
HOAMs enable great expressive power with few required language concepts (Chapter 8, Research Question 4).
• We show how the MKL language is capable of performing intensional analysis on
models, i.e., inspect and traverse the equation system (Chapter 9, Research Question 5).
• We define a formal operational semantics and related static type system for the
core of MKL. The language is an extension of a typed lambda calculus and forms
the foundation of the MKL language. We prove type safety of the core language.
(Chapter 10, Research Question 5).
• We formally define the elaboration semantics of an EOO language, i.e., the translation process from an EOO model to an equation system. We describe both an
18
1 Introduction
approach for the connection semantics as well as a solution for the problem of extraction simulation results. (Chapter 11, Research Question 4).
• We explain our prototype implementation of MKL, define the semantics of simulating a model using an external DAE solver, as well as exporting the DAE to a flat
Modelica model, i.e., a model with only equations and no components. Finally, we
verify, discuss, and evaluate our solution. (Chapter 12, Research Question 5).
1.5.3 Part III - Related Work and Concluding Remarks
In the final part, we do not make any new contributions. Instead our work is compared
to related work (Chapter 13). Finally, we state the conclusions of the thesis and outline
future work (Chapter 14).
1.5.4 Published Papers
The research results given in this thesis are partially based on the following published
papers and reports:
Journal Paper
• David Broman and Peter Fritzson. Higher-Order Acausal Models. Simulation
News Europe 19(1):5-16, ARGESIM, 2009
Peer Reviewed Conference and Workshop Papers
• David Broman and Peter Fritzson. Higher-Order Acausal Models. In Proceedings
of the 2nd International Workshop on Equation-Based Object-Oriented Languages
and Tools, pages 59-69, Paphos, Cyprus, LIU Electronic Press, 2008 (superseded
by the journal version)
• David Broman and Peter Fritzson. Abstract Syntax Can Make the Definition of
Modelica Less Abstract. In Proceedings of the 1st International Workshop on
Equation-Based Object-Oriented Languages and Tools. pages 111-126. Berlin,
Germany. Linköping University Electronic Press. 2007
• David Broman, Kaj Nyström, and Peter Fritzson. Determining Over- and UnderConstrained Systems of Equations using Structural Constraint Delta. In Proceedings of the Fifth International Conference on Generative Programming and Component Engineering (GPCE’06). pages 151-160. Portland, Oregon, USA. ACM
Press. 2006
• David Broman, Peter Fritzson, and Sébastien Furic. Types in the Modelica Language. In Proceedings of the Fifth International Modelica Conference. pages
303-315. Vienna, Austria. 2006
1.5 Thesis Outline and Contributions
19
Invited Paper
• David Broman. Growing an Equation-Based Object-Oriented Modeling Language.
In Proceedings of MATHMOD 09, Vienna, pages 1316-1324, Vienna, Austria,
2009
Technical Reports and Thesis
• David Broman. Safety, Security, and Semantic Aspects of Equation-Based ObjectOriented Languages and Environments. Licentiate thesis. Thesis No 1337. Department of Computer and Information Science, Linköping University, December,
2007
• David Broman. Flow Lambda Calculus for Declarative Physical Connection Semantics. Technical Reports in Computer and Information Science No. 1, Linköping
University Electronic Press. 2007
Papers and Reports not Included in the Thesis
The following papers and reports are of related interest, but not directly included in this
thesis. The papers were authored or co-authored during the period of this thesis work.
• Peter Aronsson and David Broman. Extendable Physical Unit Checking with Understandable Error Reporting. In Proceedings of the 7th International Modelica
Conference, Como, Italy, 2009
• David Broman. Should Software Engineering Projects be the Backbone or the Tail
of Computing Curricula?. In Proceedings of the 23th IEEE Conference on Software
Engineering Education and Training, Pages 153-156, Pittsburgh, USA, 2010
• Peter Fritzson, Adrian Pop, David Broman, and Peter Aronsson. Formal Semantics
Based Translator Generation and Tool Development in Practice. In Proceedings of
the 20th Australian Software Engineering Conference ASWEC 2009, pages 256266, Gold Coast, Queensland, Australia, IEEE Computer Society, 2009
• David Broman, Peter Aronsson, and Peter Fritzson. Design Considerations for
Dimensional Inference and Unit Consistency Checking in Modelica. In Proceedings of the 6th International Modelica Conference, pages 3-12, Bielefeld, Germany,
2008
• Peter Fritzson, David Broman, and François Cellier. Equation-Based Object-Oriented Languages and Tools. Report on the 2nd Workshop EOOLT at ECOOP 2008.
Object-Oriented Technology. ECOOP 2008 Workshop Reader, Volume 5475 of
LNCS, pages 18-29, Springer-Verlag, 2009 (Invited)
• Peter Fritzson, David Broman, François Cellier, and Christoph Nytsch-Geusen.
Equation-Based Object-Oriented Languages and Tools. Report on the Workshop
EOOLT 2007 at ECOOP 2007. Object-Oriented Technology. ECOOP 2007 Workshop Reader, Volume 4906 of LNCS, pages 27-39, Springer-Verlag, 2008 (Invited)
20
1 Introduction
• Peter Fritzson, François Cellier, and David Broman (Eds.). Proceedings of the 2nd
International Workshop on Equation-Based Object-Oriented Languages and Tools.
Cyprus, July 2008. ISSN 1650-3686, LIU Electronic Press
• Kristoffer Norling, David Broman, Peter Fritzson, Alexander Siemers, and Dag
Fritzson. Secure Distributed Co-Simulation over Wide Area Networks. In Proceedings of the 48th Conference on Simulation and Modelling (SIMS’07). Göteborg,
Sweden, Linköping University Electronic Press, 2007
• Peter Fritzson, Peter Aronsson, Adrian Pop, Håkan Lundvall, Kaj Nyström, Levon
Saldamli, David Broman, Anders Sandholm. OpenModelica - A Free Open-Source
Environment for System Modeling, Simulation, and Teaching. In Proceedings of
the 2006 IEEE Conference on Computer Aided Control Systems Design, Munich,
Germany, 2006 (Invited)
• David Broman and Peter Fritzson. Ideas for Security Assurance in Security Critical Software using Modelica. In Proceedings of the Conference on Modeling and
Simulation for Public Safety, pages 45-54, Linköping, Sweden, 2005
• Peter Fritzson, Peter Aronsson, Håkan Lundvall, Kaj Nyström, Adrian Pop, Levon
Saldamli, and David Broman. The OpenModelica Modeling, Simulation, and Development Environment. In Proceedings of the 46th Conference on Simulation and
Modeling, pages 83-90, Trondheim, Norway, 2005
1.5.5 Origin of Contributions
The most significant part of the research work and contributions in this thesis originates
entirely from the author of the thesis. However, because several of the published papers
included in this thesis have co-authors, we detail the exact origin of the contributions
below.
Part I - The Modelica Language
The work on how to specify the Modelica language [24] and strategies for growing
equation-based languages [19] are done solely by the author with Peter Fritzson as supporting supervisor.
The work on Modelica types [27] was carried out by the author, where both Peter
Fritzson and Sébastien Furic co-authored the publication. They contributed as discussion
partners and through proofreading the manuscript.
The idea and formalization of the work on the structural constraint delta [28] was
carried out solely by the author. Co-authors Kaj Nyström and Peter Fritzson contributed
as discussion partners, as proofreaders, and with shorter sections in the original paper.
Part II - The Modeling Kernel Language
The published work in this part concerns higher-order acausal models (HOAM) [25, 26].
The co-author Peter Fritzson has been supervisor of the work, contributing with feedback
and proofreading.
1.6 Research Method
21
The semantics of the MKL language has been developed solely by the author of the
thesis, where Jeremy Siek has been supporting co-supervisor.
The implementation, validation, and written manuscript are performed entirely by the
author of the thesis.
1.5.6 Reading Guidelines
We will now give some brief guidelines for reading the thesis. The aim of this thesis is
to have a broad audience, where readers might come from either different engineering
fields or from the field of computer science. The two main parts of the thesis (Part I about
Modelica and Part II about MKL) are self contained and can be read independently of
each other. For each of the parts, there is an introduction chapter which is recommended
reading before proceeding with the other chapters.
Readers from different engineering fields with an interest in modeling and a background of e.g., Modelica might be especially interested in Chapter 5 about types in Modelica, as well as the ideas of higher-order acausal models, presented in Chapter 8.
Readers with a background of designing modeling languages in general and Modelica
in particular might be interested in Chapter 4 about growing an EOO language. Part II
presents language concepts that are not directly related to Modelica, but can be of interest
for further extensions of such a language. Chapters that can be of particular interest
are: introduction to functional programming in MKL (Chapters 7), modeling with higherorder acausal models (Chapter 8), using and inspecting the content of models (Chapter 9),
and description of elaboration semantics (Chapter 11).
Readers with a computer science background would perhaps be most interested in Part
II. If the reader has a more theoretical programming language background, Chapter 10
with formal operational semantics and type safety proofs could be of interest.
1.6 Research Method
There are several different paradigms on how to perform research within engineering and
computer science. The ACM Task Force on the core of computer science suggests three
different paradigms for performing research within the discipline of computing [42]:
1. Theory. In this paradigm, the discipline is rooted in mathematics, where the objects of study are defined, hypotheses (the theorems) are stated, and proofs of the
theorems are given. Finally, the result is interpreted.
2. Abstraction (modeling). The second paradigm is rooted in experimental scientific
methods. First, a hypothesis is formulated, followed by the construction of a model
and/or an experiment from which data is collected. Finally the result is analyzed.
3. Design. The third paradigm is rooted in engineering and consists of stating requirements, defining the specification, designing and implementing the system, and finally testing the system. The purpose of constructing the system is to solve a given
problem.
22
1 Introduction
Theory is the fundamental paradigm in mathematical science, the abstraction paradigm in
natural science, and design in the discipline of engineering. We agree with the statement
that is pointed out by Denning et. al. [42], that all three paradigms are equally important
and that computer science and engineering consist of a mixture of all three paradigms. In
this work, we have used different paradigms for the different parts of the work.
In the work on types in the Modelica language (Chapter 5), the type concept of Modelica is studied and interpreted and a concrete syntax of types for Modelica is described.
The closest paradigm used in this work is design, where the designed artifact is the grammar for types and the interpreted prefix definitions. The correctness of the grammar is
verified using the parser generator tool ANTLR [119]. In this case, the Modelica specification itself can be seen as the requirements specification and the produced artifact is an
interpretation of this specification.
In the work on structural constraint delta (Chapter 6) we define a new approach and
an algorithm for determining over- and under-constrained systems of equations. This
research can be assigned to both the theory and the design paradigms. From the theory
point of view, if a theorem was formulated for the correctness of the algorithm, a proof
would justify the correctness of the algorithm. On the other hand, from a design point
of view, the requirement of detecting and isolating the error before elaboration can be
seen as a specification, and an implementation of the algorithm as the system. Because
Modelica’s semantics is not formally defined, it is not possible to conduct any proof of
the correctness of the algorithm in relation to the elaboration semantics. Hence, we use a
test procedure where the correctness of the algorithm is tested using different test models,
where the model is executed in the commercial Modelica tool Dymola version 6 [45],
and compared to an implementation of the algorithm given in Chapter 6. We should note
that this test only checks the correctness of the algorithm, and does not verify that the
approach of the structural constraint delta actually helps the user to detect the error and
isolate the fault.
Finally, our work of being able to design EOO language constructs in the modeling
kernel language (MKL) (Part II) has been verified using basic engineering principles
of testing as well as conducting proofs of the language’s properties. For the testing and
verification, a set of models have been implemented in both Modelica and using a standard
library in MKL. The MKL models have then been translated into flat Modelica code. The
results of simulating both the translated and the native Modelica model have then been
compared. Also, the models have been simulated using MKL, where the simulation result
has been compared with Modelica simulations. For the theory part, we have proved type
safety for a core language of MKL. This gives us higher confidence of the correctness
of our approach, but can of course not guarantee the correctness of the correspondence
between the formal semantics and the implementation.
Part I
The Modelica Language
23
2
Introduction to Modelica
is a standardized language aimed primarily for modeling and simulation
of complex physical systems. The first language specification 1.0 [101] was released in September 1997. Since then, the current specification 3.2 [104] has evolved to
be a specification of a language that has a large number of complex constructs.
During these past 13 years, the Modelica user community has grown to become
fairly large. Modelica has been used successfully in industry and the Modelica standard library (MSL) has evolved to include domains such as electrical, mechanical, hydraulic, fluid, thermal and control. The dominating Modelica tool has for a long time
been the commercial tool Dymola [45]. However, during recent years, alternative tools
have emerged; both open source (e.g., OpenModelica [53, 117], Scicos [73, 106], and
JModelica.org [5, 78]) and commercial environments (e.g., MathModelica System Designer [91], MOSILAB [112], SimulationX [76], LMS Imagine.Lab AMESim [89], and
MapleSim [90]).
Modelica Association [100] is responsible for both the language specification as well
as the Modelica standard library. The author of this study has been a member of the
Modelica language design group since 2005. The work presented in this part has been
developed 2005 to 2010 contains both discussions and analysis of the current language
specification (Chapters 3-5) as well as proposed extensions (Chapter 6). This part of the
thesis consists of the following chapters:
M
ODELICA
• Chapter 2 - Introduction to Modelica. In this introductory chapter we first give a
brief informal overview of the Modelica language from a modeling point of view.
This is followed by a description of Modelica’s compilation and simulation process.
• Chapter 3 - Specifying the Modelica Language. This chapter concerns the problem of having a large and informal language specification. We discuss different
aspects of formulating the Modelica language.
25
26
2 Introduction to Modelica
• Chapter 4 - Growing the Modelica Language. We discuss how the Modelica
language can be planned for growth, i.e., how the language can be extended over
time.
• Chapter 5 - Types in the Modelica Language. We investigate and analyze the
concept of types in the Modelica language as well as proposing a concrete syntax
for describing Modelica types.
• Chapter 6 - Over- and Under-Constrained Systems of Equations. In this chapter
we propose a technique for detecting and isolating over- and under-constrained
systems of equations in EOO languages. We test the described approach, called
structural constraint delta, on a subset of the Modelica language. However, the
approach is not limited to Modelica and is applicable for EOO languages in general.
2.1
Equation-Based Modeling in Modelica
In this section we illustrate some important and fundamental concepts in modeling with
Modelica. A comprehensive description of the language is given by Fritzson [51].
The basic structuring element in Modelica is the class . There are several restricted
class categories with specific keywords, such as model, record (a class without equations), and connector (a record that can be used in connections). A class contains
elements, which can be other class definitions, extends elements (for inheritance of other
classes), or components (instances of classes).
The main difference compared to traditional OO languages is that instead of methods,
Modelica primarily uses equations to specify behavior.
As a brief introduction to Modelica, we present a model of a simple electrical circuit (Figure 2.1). On the left hand side the textual representation of the circuit is given
model Circuit
Resistor R1(R=10);
Capacitor C(C=0.01);
Resistor R2(R=100);
Inductor L(L=0.1);
VsourceAC AC;
Ground
G;
equation
connect(AC.p, R1.p);
connect(R1.n, C.p);
connect(C.n, AC.n);
connect(R1.p, R2.p);
connect(R2.n, L.p);
connect(L.n, C.n);
connect(AC.n, G.p);
end Circuit;
Figure 2.1: Modelica model of an electrical circuit.
2.1 Equation-Based Modeling in Modelica
27
and on the right hand side the graphical representation. Typically, a Modelica modeling
environment lets the user model the system in either the graphical or the textual view.
Now, let us consider the textual representation. The first six lines of code represent
the components of the model. These have a direct correspondence to the components in
the graphical view. In the first component declaration
Resistor
R1(R=10);
the indentifier Resistor is a class reference, R1 is a component name, and R=10 is a
modification that sets the resistance R equal to 10.
The last seven lines that are part of the equation section are called connectequations. These equations are used for connecting connectors (also called ports) together. For example, the equations connect(AC.p, R1.p) and connect(R1.p,
R2.p) state that connectors AC.p, R1.p, and R2.p are connected together. Such a set
of connected connectors is called a connection set. Note that because models are hierarchically defined, names to particular components are specified using a dot-notation, e.g.,
R1.p is the positive connector of component R1.
Now consider the following example of a connector used for acausal connections in
the electrical domain:
connector Pin
Real v;
flow Real i;
end Pin;
where v is the potential variable representing voltage and i the flow variable for electrical
current. The connection set {AC.p, R1.p, R2.p} is then during the elaboration phase
translated into two equality equations for the potential variables:
AC.p.v = R1.p.v;
R1.p.v = R2.p.v;
and one sum-to-zero equation for Kirchoff’s current law:
AC.p.i + R1.p.i + R2.p.i = 0;
Variables in connectors can also have the prefixes input or output stating that these
variables are used for causal connections.
Now, let us consider how the models of the components in Figure 2.1 are defined. A
first observation can be made that all these components have two ports (except for the
ground component that has one port). Thus it is useful to define a “base” TwoPin model
as follows:
28
2 Introduction to Modelica
model TwoPin "Superclass of model components with two pins"
Pin p, n;
Voltage v;
Current i;
equation
v = p.v - n.v;
0 = p.i + n.i;
i = p.i;
end TwoPin;
This component has two connectors p and n defined as an instance of the connector class
Pin. The variable v defines the voltage drop over the component using the equation
v = p.v - n.v. The variable i is the current into the pin p.
To define a model for an electrical capacitor we can now extend our base class TwoPin
and add a declaration of a variable for the capacitance and one equation expressing the
capacitor’s behavior:
model Capacitor "Ideal electrical capacitor"
extends TwoPin;
Real C "Capacitance";
equation
C*der(v) = i;
end Capacitor;
The keyword extends denotes inheritance from one or more base classes. Elements
and equations are inherited from the parent. The equation C*der(v) = i contains the
expression der(v) meaning the derivative of v.
When extending or declaring an element, we can also add modification equations .
The simplest form of modification is binding a value to a variable:
Resistor R1(R=100);
It is also possible to alter the internal structure of a component when declaring or extending it, using redeclarations. The redeclare construct changes the class of the
component being replaced. There are two restrictions on this operation:
1. The component we are replacing must be declared as replaceable.
2. The replacing class’s type must be a subtype of the type of the component being
replaced.
Consider now the following example
model A
replaceable Resistor R1(R=100);
end model A;
model B
extends A(redeclare TempResistor R1);
end B;
where we define a model B by extending from model A and at the same time change
resistor R1 to be a TempResistor.
2.2 The Modelica Compilation and Simulation Process
29
This short introduction to Modelica only describes a very small part of the Modelica
language. However, there should be enough details to understand the rest of Part I of the
thesis. The language contains many more constructs that are outside the scope of this
thesis. Some of these constructs are:
•
•
•
•
•
•
•
•
Arrays, vectors, and matrices.
Side-effect free functions and algorithm sections.
When- and if-equations for expressing hybrid models.
Conditional components for selecting components during elaboration.
Packages for structuring source code into modules.
Overloading of operators.
Stream connectors.
Mapping of models to execution environments (used in for example hardware-inthe-loop simulations.).
See Fritzson [51] and the Modelica specification 3.2 [104] for descriptions of these and
other advanced constructs in Modelica.
2.2 The Modelica Compilation and Simulation
Process
Figure 2.2 outlines a typical compilation and simulation process for a Modelica software
tool. The input (left hand side of the figure) to the process is a Modelica model, which
can compose and reference a large set of additonal Modelica models. The first phase that
is carried out is standard lexical analysis and parsing. Output from this step is an abstract
syntax tree (AST) . This phase can, depending on the implementation, be performed in
several stages, where each stage simplifies and normalizes the form of the AST.
The second phase of the process is the elaboration, where the AST is transformed into
a hybrid DAE . A hybrid DAE consists of variable declarations, the differential-algebraic
equation system (for continuous-time behavior), algorithm sections, and when-clauses
for triggering discrete-time behavior. During this phase the model is also checked for
errors, such as conformance of types.
Figure 2.2: Outline of a typical compilation and simulation process for a Modelica
language tool.
30
2 Introduction to Modelica
The two first phases, lexical analysis and parsing followed by elaboration, is often
referred to as the compiler front-end. Semantics discussed in this thesis is focused on this
part.
The next phase of the compiler, the back-end, is first transforming and manipulating
the equation system to make it solvable. Key aspects of this process are the use of Pantelides algorithm [118], block lower triangular form (BLT) [70, 71], dummy-derivatives
[94], and tearing [49]. Typically the DAE is reduced to an index one problem and then
solved with a DAE solver such as DASSL [121] or the IDA solver within the SUNDIALS solver suite [68]. The equation system could also be translated and sorted to form
an ODE, to be solved with a numerical integration method, such as Runge-Kutta. Typically, the right-hand side of the equation system (for an ODE) or the residual function
(for an DAE) is translated to executable code, where the typical target language is C. Finally, these generated functions together with a main program is linked together with a
numerical solver and then compiled into an executable file.
The process of phases two and three is typically performed at compile time. The last
step, when the model is simulated (executed) is often referred to as the run time semantics
of the process. Output from this process is typically a file containing simulation data for
the state variables. The data is then later visualized using a graphical user interface (GUI) .
The process of elaboration, where a EOO model is translated into an equation system,
can informally be described to perform at least the following three main activities:
• Type checking of models. Check that parameterized models conform to the type
rules of the language and that basic operations and function calls are type correct.
For example, a function having one argument cannot be applied to two arguments
and a plus operator cannot have a string as its left operand and an integer as its right
operand, etc.
• Collapsing the instance hierarchy. During this activity, new unknowns and equations are created for sub-components of a model. For example, if a model contains
two resistors R1 and R2, where R1 is parameterized with 10 ohm, and R2 with 50
ohm, two equations are created u1 = 10 * i1 and u2 = 50 * i2. Moreover, unknowns, such as the voltage drop over the components must be different
for the components. Hence, u1 and u2 must be different unknowns.
• Connection semantics. Acausal ports contain flow and potential variables, where
the former must sum-to-zero at connection points and the latter must have the same
potential at the connection point. This activity generates equations and unknowns
to enable acausal modeling.
We postpone the discussion about type checking of Modelica models to Chapter 5 and 6
and the discussion of connection semantics to Chapter 11.
We will now present a very simple example to give an intuition of how the instance
hierarchy of a model is collapsed. The example only illustrates the basic principles for
composed models, together with Modelica’s inheritance mechanism. In a compiler that
handles the full Modelica language this is one of the most substantial parts due to number
of constructs in the language and its complicated look-up mechanism.
Consider the following Modelica models:
31
2.3 Chapter Summary and Conclusions
model B
Real y;
Real x;
equation
y=der(x);
end B;
model C
Real z=10;
Real t;
equation
t=z*2;
end C;
model A
extends C(z=5);
B b;
end A;
The task is to elaborate model A. This means that from the code in model A, we should
extract the corresponding system of equations. Examining model A, we find that it extends
(inherits from) C. Our action is then to simply copy the contents of model C into our
working copy of model A. The modification equation to variable z in the extends clause
replaces the declaration equation to variable z in C. All modifications are resolved as
equations so the overriding modification z=5 is put in the equation section. The result so
far is:
model A
Real z;
Real t;
B b;
equation
z=5;
t=z*2;
end A;
We do not have to do anything about declarations of variables with predefined types (e.g.,
Real, Integer, and Boolean). However, the component b must be elaborated because B is not of a predefined type. We investigate the model B and find that it contains
the declarations Real y and Real x. These declarations and all equations in the model
B will now be inserted in our working model A with the prefix b. as we have now entered
the namespace of the component b. The elaboration is now complete because there are
only predefined types left in our working model. The final result of this basic elaboration
(excluding type checking and connection semantics) is
model A
Real z;
Real t;
Real b.x;
Real b.y;
equation
b.y=der(b.x);
z=5;
t=z*2;
end A;
2.3 Chapter Summary and Conclusions
We have in this chapter given a brief overview of the Modelica language. We have presented modeling examples within the electrical domain and explained the overall structure of the Modelica compilation and simulation process. Finally, we have given a short
overview of the elaboration phase in Modelica.
32
2 Introduction to Modelica
3
Specifying the Modelica Language
Modelica language specification defines a formal concrete syntax, but the semantics is informally described using natural language and with examples. This makes
the language’s semantics hard to interpret unambiguously and to reason about, which
affects both tool development and language evolution. Even if a completely formal semantics of the Modelica language can be seen as a natural goal, it is a well-known fact
that defining understandable and concise formal semantics specifications for large and
complex languages is a very hard problem. In this chapter, we will discuss different aspects of formulating a Modelica specification; both in terms of what should be specified
and how it can be done. Moreover, we will further argue that a "middle-way" strategy can
make the specification both clearer and easier to reason about. An idea for a proposal is
outlined where the current informally specified semantics is complemented with several
grammars, specifying intermediate representations of abstract syntax. We believe that this
kind of evolutionary strategy is easier to gain acceptance for, and is more realistic in the
short-term, than a revolutionary approach of using a fully formal semantics definition of
the language. This chapter is organized as follow:
T
HE
• We introduce and motivate the need for a middle-way strategy for specifying the
Modelica language (Section 3.1).
• Different ways of specifying a Modelica specification are discussed and analyzed
(Section 3.2).
• We explain the idea of specifying abstract syntax for improving the specification
(Section 3.3).
33
34
3.1
3 Specifying the Modelica Language
Introduction and Motivation
In this section we first discuss different alternatives of specifying a language specification
and then briefly describe previous attempts of specifying subsets of Modelica. Finally, we
introduce the idea of using several intermediate languages as middle-way strategy.
3.1.1 Unambiguous and Understandable Language Specification
The natural goal of a language specification is to be unambiguous, so that tool implementors interpret the specification in exactly the same way. At the same time, it is important
that the specification is easy to understand for the intended audience. Unfortunately, it is
not that easy to meet both of these goals when describing a large and complex modeling
language such as Modelica. There are several specification approaches with different pros
and cons. Hence, the overall problem is to find an approach that satisfies the specification
goals in the best possible way.
If the language is described using formal semantics, e.g., structured operational semantics [126], the language semantics can in some cases be proved to have certain properties, such as type safety [124, 151]. However, to understand and interpret a formal
language specification requires a rigorous theoretical computer science knowledge. Furthermore, even if great effort has been spent during the recent decades in formalizing
mainstream programing languages, only a few, e.g., Standard ML [98], are actually fully
formally specified. Accordingly, it turns out to be a very hard task to specify an understandable and concise formal specification of an existing complex language.
Alternatively, if the language semantics is described using natural languages, e.g.,
plain English text describing the semantics, it might be easy for software engineers to
understand the specification. Many languages are described in this way, for example
Java [65], C++ [75], and Modelica [102]. However, ease of understanding does not imply
that different individuals interpret the specification in the same way. It is a well known
fact that it is very hard to write unambiguous natural language specifications, and perhaps
even harder to verify their consistency.
3.1.2 Previous Specification Attempts
Several previous attempts have been made to formalize and improve the specification of
the Modelica language. The most obvious one is the further development of the official
language specification itself, conducted by the Modelica Association. The work that resulted in version 3.0 of the language specification contained substantial restructuring and
a more detailed description of the semantics of the language. However, it is not planned
to include any formal descriptions.
Three earlier attempts for improving the specification of the Modelica language have
previously been conducted. The first one, started already in 1998 by Kågedal and Fritzson [84, 85] tried to describe the language using Natural Semantics [81]. As the specification grew over time it has evolved into the OpenModelica compiler [117]. The second
attempt by Mauss [95] described the instance creation of the elaboration, but not the type
checking. Finally, our work on Modelica types [27] (described in the next Chapter), tries
to clarify the type concept in Modelica, but does not involve the actual type checking
3.1 Introduction and Motivation
35
algorithm. A more in depth discussion of related work is given at the end of the thesis in
Section 13.2.
A common denominator for all these isolated formal specification attempts is that
they have been conducted in parallel with the official language specification. Even if a
proposed alternative specification covers large portions of the language, it will not be used
as a specification by the community if it is not replacing the official specification. If there
are two specifications of the same concept, how do we then know which one is valid if
they are not consistent? Nevertheless, these formal specification attempts are still very
important to promote understanding and discussion about the informal semantics. It is of
great importance that these works gradually find their way into the official specification.
The problem is how to make this possible in practice because all attempts so far only
model subsets of the real language.
3.1.3 Abstract Syntax as a Middle-Way Strategy
Improving the natural language description of the Modelica specification is an obvious
way of increasing the understandability and removing ambiguity. However, previous work
on formalization of the complete semantics of subsets of the language has shown to be
complex and resulting in very large specifications. Hence, there is a concrete and practical
need to find a "middle-way" strategy to improve the clarity of the complete language, not
just subsets. This strategy must be simple enough to not require in depth theoretical
computer science knowledge of the reader, but still precise enough to avoid ambiguities.
When a compiler parses a Modelica model, the result is transformed into an abstract
syntax tree (AST) [4, 124]. The abstract syntax can be specified using a context-free
grammar.
The internal representation of an AST is often seen as a tool implementation issue,
and not as something that is defined in a language specification. Nevertheless, in this
chapter we sketch the idea that an intermediate representations between the transformation steps (recall Figure 2.2) should be described by specifying its abstract syntax. Note
that this abstract syntax is only intended as an abstract concept specified in a language
specification and read by humans. It is not intended for implementation.
However, specifying different forms of abstract syntax cannot replace the semantic
specification needed in the transformation process because the syntax only describes the
structure of a Modelica model, while the semantics states the meaning of it. Hence,
in the short term, this specification complements the current informal specification, by
clarifying exactly what both the input and the output structure of a transformation are.
By following this evolutionary strategy, the semantic description may then be gradually specified more formally. However, this is not straight forward when considering the
whole Modelica language. The main purposes of including abstract syntax definitions in
the specification can be summarized to be:
1. Specifying Valid Input. Increase the clarity of what valid Modelica actually is, i.e, to
make sure that different tools reject and accept the same models.
2. Specifying Expected Output. Remove confusion of what the actual outcome of executing a Modelica model is.
36
3 Specifying the Modelica Language
3. Promoting Language Simplification. The Modelica language has been identified to
be sometimes more complicated than necessary (e.g., relations between the general class and restricted classes). An abstract syntax formulation can be used as a
guidance tool for identifying the most useful reformulations needed.
Part of the first item is already specified using the concrete grammar. To increase the level
of detail that can be specified of the abstract syntax, we will later on suggest an informal
approach to include context-sensitive information in the abstract grammar specification.
This rules out parts of the informal semantics used for rejecting invalid models. However, large parts of the rejecting semantics must still be described using another semantic
specification form.
3.2
Specifying the Modelica Language
Defining a new language from scratch with an unambiguous and understandable language
specification is a difficult and time consuming task. Developing and enhancing a language
over many years and still being able to keep the language backwards compatible and the
specification clear, is perhaps an even more challenging mission. In the previous section,
we described this problem with the current specification, motivated the need for improvement, and briefly introduced a proposed strategy. In the beginning of this section, we will
focus on the question what should actually be specified in the Modelica specification. At
the end of the section, we will discuss how this specification can be achieved by surveying some different specification approaches and compare how they relate to the abstract
syntax approach.
At a high level, the syntax and semantics of Modelica can be divided into two main
aspects:
• Transformation, i.e., the process of transforming a Modelica source code model
into a well defined result. Depending on the purpose, the result can either be an
intermediate form of a hybrid DAE, or the final simulation result.
• Checking, i.e., rules describing what a valid Modelica model actually is. These
rules should unambiguously describe when a tool should reject the input model as
invalid.
Both these aspects are important for a clear-cut result, so that tool vendors can create
compatible tools.
3.2.1 Transformation Aspects - What is Actually the Result of an
Execution?
In the introduction section of the Modelica specification 3.2 [104], it is stated that the
scope of the specification is to define the semantics of the translation to a flat Hybrid
3.2 Specifying the Modelica Language
37
DAE and that it does not define the result of a simulation. A mathematical notation of the
hybrid DAE is given, but no precise and complete output is defined.
However, many constructs given in the specification are not transformed to more primitive constructs during this translation to a Hybrid DAE. Hence, the semantics of these
constructs (e.g., when-equations, algorithm sections), are implicitly defined, even if the
specification states that this should not be the case.
Therefore questions arise: what is actually the transformation process? What is the
expected result of the execution? We would argue that the answer to these questions
would differ depending on who you ask because the current specification is open for
interpretation.
Static vs. Dynamic
In the previous description of the compilation and simulation process, it was assumed
that the process was compiled and not interpreted. This is not a specification requirement,
even if it is common that tools are implemented as compilers. The definitions of static and
dynamic semantics are often confusing in relation to compile-time and simulation-time.
Some people will argue that the dynamic semantics is only the simulation sub-process and
that the elaboration and equation transformation as well as the code generation phases are
the static semantics. However, in Modelica it is possible to define a recursive model that
refers to itself, thus resulting in an infinite loop during the elaboration process. In such a
case, it questionable if the elaboration process can be called static.
From the above discussion, it is clear that we need to have a precise definition of the
input and the output of the elaboration process. Whether the two last sub-processes should
be part of the specification is an open design issue, but it is obviously important that the
decision is made if it should be completely included or removed.
3.2.2 Checking Aspects - What is actually a Valid Modelica
Model?
In the current specification, it is hard to interpret what valid Modelica input is, i.e., it is
difficult for a tool implementor to know which models that should be rejected as invalid
Modelica. A restrictive abstract syntax definition can help clarifying several issues.
Besides specifying the translation semantics of a model, a language specification typically describes which models that should be treated as valid, and which should not. By
an invalid model we mean an transformation that should result in an error report by the
tool. In order for different tool vendors to be able to state that exactly the same models
are invalid, when and how to detect model faults must be clearly and precisely described
in the language specification. Unfortunately, this is not as easy as it might seem.
Basically, rules in a specification for stating a valid model can be specified by using
one of the following strategies, or a combination of both:
• Specify rules that indicate valid models. All models that do not fit to these rules are
assumed to be invalid.
• Assume that all models are valid. Explicitly state exceptions where models are not
valid.
38
3 Specifying the Modelica Language
The current Modelica specification mostly follows the latter approach. Here the concrete
syntax constrains the set of legal models at a syntactic level. Then, informal rules given
in natural language together with concrete examples state when a model can be legal or
illegal.
The problem with this approach is that it is very hard for a tool vendor to be sure that
a tool is compliant with the specification.
Time of checking
Detecting that a model is invalid can take place at different points in time during the
compilation and simulation phase. Even if this can be regarded as a tool issue and not a
language specification detail, the checking time has great implications on a tool’s ability
to guarantee detection of invalid models.
Figure 3.1 outlines a simplified view of the earlier described compilation and simulation process, where the three sub-processes of equation-transformation, code generation
and simulation are combined into one transformation step. Also, the lexical analysis and
parsing steps are omitted from the figure.
Figure 3.1: Possible points in time when the checking can occur.
The figure shows five (T1 - T5) conceptual points in time where the checking and rejection of models can take place. Starting from the end, T5 illustrates the final step of
checking that the simulation result data is correct according to some requirements. This
checking can normally not be conducted by a tool, but only by humans who have the
domain knowledge.
The checking at point T4 takes place during simulation of the model. This is what
many would refer to as dynamic checking because it is performed during runtime. Errors
which can occur here are for example numerical singularities after events or array outof-bound errors. Because Modelica does not have an exception handling mechanism, it
is implicitly assumed that the tool exits with an error statement. Checking point T3 is
performed after the elaboration phase. This can for example concern controlling that the
number of equations equals the number of unknowns.
Even if it is not stated in the Modelica specification, T2 is our interpretation of the
specification where the type checking takes place. Here, the naming of this kind of checking is often a source of confusion. If the elaboration phase is regarded as the static semantics, some people call this static type checking. However, because the elaboration phase
is the major part of the semantics described in the specification, and it involves complex
transformation semantics, this can be viewed as something dynamic from an interpretive
semantics point of view, or as something static from a translational semantics point of
view. Using an interpretive semantics style, T2 would involve dynamic type checking.
Following this argumentation, then T1 would represent static type checking, i.e., the
types in the language are checked before elaboration. This reasoning is analogous to
39
3.2 Specifying the Modelica Language
dynamic checking in languages such as PHP and Common LISP, compared to static type
checking in Haskell, Standard ML, or Java. Even if the Modelica specification does not
currently support this kind of static checking, it has a major impact on the ability to detect
and isolate for example over- and under-constrained systems of equations or to enable
separate compilation.
3.2.3 Specification Approaches - How can we State What it’s all
About?
When it is clear what to specify, the next obvious question is how to specify it. There are
several specification approaches, and we have briefly mentioned some of them earlier in
this chapter.
As evaluation criteria, it is natural to use the specification goals of understandability 1
and unambiguity. Furthermore, it is also of interest to estimate the expressiveness of
the approach, i.e., how much of the intended specification task can be covered by the
approach.
In the following table, a number of possible specification approaches are listed, with
our judgements of the evaluation criteria.
Approach
Natural language description
Formal semantics
Abstract Syntax Grammar
Concrete Syntax Grammar
Test suite
Reference Implementation
Understandability
High-Medium
Low
Medium
Medium
High
Medium
Expressiveness
High
Medium
Medium
Low
High
High
Unambiguous
Low
High
High
High
Medium
High
Table 3.1: Possible specification approaches with our judgements of the evaluation
criteria.
A natural language specification can be understandable and expressive, depending on the
size and quality of the text, but easily leads, as we have discussed earlier, to ambiguous
specifications. Using a formal type system together with formal semantics [124] is here
seen as having low understandability because it requires high technical training. It is
however very precise and fairly expressive.
The expressiveness of the abstract syntax is stated as higher than the concrete syntax
because we can introduce context dependent information in the grammar using metavariables. An example of this will be given in the next section.
We have also included approaches such as the use of a test suite and reference implementation. The approach to use a test suite as a specification can be an interesting
complement to abstract syntax and informal semantics. However, it is very important to
1 Understandability is of course a very subjective measurement. In this context, we have chosen to also
include the level of needed knowledge to understand the concept, i.e., a concept requiring an extensive computer
science or mathematical background results in lower understandability rating.
40
3 Specifying the Modelica Language
state which description that has precedence if ambiguities are discovered. Finally, a reference implementation can also be seen as a specification, even if it could be hard to get
a good overview over it if the language is large and complex.
3.3
An Abstract Syntax Specification Approach
In the following section we will briefly discuss the idea to use abstract syntax as part
of the Modelica specification. Initially, the different abstract syntax representations are
outlined in relation to the transformation process described in Section 3.2.1, followed by
a discussion about the specification and representation of the syntax.
3.3.1 Specifying the Elaboration Process
An Abstract Syntax Tree (AST) can be seen as a specific instance of an abstract syntax.
Transformation processes inside a compiler can be defined as transformations from one
intermediate representation to another. ASTs are a natural form of intermediate representation.
Consider Figure 3.2, where the elaboration process is shown with surrounding ASTs.
The first step in the process is the ordinary scanning and parsing step, which is formally
defined in the specification using lexical definitions and concrete syntax definitions using
Extended BNF.
Complete AST (C-AST)
This step transforms into the first tree called Complete AST (C-AST), which is a direct
mapping of the concrete syntax. Although this is a natural step in a compiler implementation, it is of minor interest from a specification perspective.
Simplified AST (S-AST)
From the C-AST, a simplification transformation translates the C-AST into a simplified
form called Simplified AST (S-AST). This transformation’s goals are:
• Desugaring : The process of removing so called syntactic sugar, which is a convenient syntactic extension for the modeling engineer, but with no direct implication
on the semantics. Example of such desugaring of a model is to collect all equation
Figure 3.2: Modelica’s compilation process divided into intermediate representations in the form of abstract syntax trees (ASTs).
3.3 An Abstract Syntax Specification Approach
41
sections into one list because the Modelica syntax allows several algorithm and
equation sections to be defined in a model.
• Normalizing Transformations : Minor transformations and operations that help the
S-AST to be a canonical form which is more suitable as input to the elaboration
process. For example assigning correct prefixes to subelements.
• Checking model validity : One of the purposes with S-AST is that it is more restrictive than the C-AST. Hence, some C-AST constructs are not valid S-AST. This
restriction gives the possibility to ensure certain model properties, which in the
current Modelica specification are described using informal natural languages. For
example, which kind of restricted classes is the record class allowed to contain as
its elements?
The S-AST can be seen as a simplified internal language analogously to the bare language
of Standard ML [98]. However, initially, we do not see a similar short and precise way of
specifying the transformation from C-AST to S-AST because of the size and complexity
of the language.
Hybrid DAE AST (HDAE-AST)
Besides S-AST, the output of the elaboration phase called Hybrid DAE AST (HDAEAST) is proposed to be specified formally in the specification. The HDAE-AST must not
just be a high-level mathematical description of an Hybrid DAE, but an explicit syntax
description describing a complete specification of what the actual output of the elaboration
phase is. This does not only include equations and variables, but function definitions,
algorithm sections, when-equations and when-statements. Even if this information is
possible to derive from the current specification, it would be a great help for the reader to
actually know what the output is, not just assume it.
Note that our approach suggests that the language specification should initially include
a precise description of the possible structures of the ASTs; specifying input and output
to the transformation process. The semantics of the transformation must still be described
using another approach that initially could still be an informal description.
3.3.2 Specifying the Abstract Syntax
The specification of the syntax must be described using some kind of grammar. The
syntax can be specified using a context-free grammar, e.g. in Backus-Naur Form (BNF).
However, we propose a more abstract definition of a grammar, where certain meta-variables
range over names and identifiers.
For example, by stating that a meta-variable Rr ranges over names (identifiers with
possible dot-notation) referencing a record, we have introduced a contextual dependency in the grammar. The grammar declaratively states the requirement that this name
must after lookup be a record, without stating how the name lookup should be performed.
42
3 Specifying the Modelica Language
The latter must of course also be described in the specification, but in this way the different issues are separated. Consequently, this grammar is not intended to be used directly
by a parser generator tool such as Yacc, but as a high-level specification which is less
open for interpretation.
3.3.3 The Structure of an Abstract Syntax
Depending on the purpose and language for an abstract syntax, the structure of the syntax
itself can be very different.
When specifying a simple functional languages, it is common that the grammar of the
abstract syntax only has one non-terminal, namely a term [124]. Hence, all evaluation
semantics is performed on this node type only, and all terms can be nested into each other.
This gives a very expressive language, but the constraining rules ensuring the validity of
an input program must be given in another form. This form is normally a formal type
system, describing allowed terms.
Another method is to describe the abstract syntax with many non-terminals; more
than needed for a production compiler. In for example the Modelica case, the different
restricted classes: model, block, connector, package, and record would not
be represented as one non-terminal class, but as different non-terminals. This structure
would be more verbose, but also give the possibility of more precisely describing relations
between restricted classes.
Somewhere inbetween those two extremes is for example the SCODE representation
used in the earlier RML specification [84] and the current OpenModelica implementation.
For the specification purpose, we suggest to use the most verbose alternative, i.e. the
second alternative using many non-terminals. The rational for this choice is basically that
this more restrictive form gives more information about what the actual input and output
of the elaboration processes are.
3.3.4 A Connector S-AST Example with Meta-Variables
To give a concrete example where a grammar for S-AST can improve the clarity compared to the current informal specification, we take the restricted class connector as
an example. In the Modelica specification it is stated that for a connector "No equations are allowed in the definition or in any of its components". What does this mean?
That no equations are allowed at all? Are declaration equations allowed, for example
Real x = 4? Obviously, it is not allowed to have instances of models that contain
equations, but is it allowed to have models that do not contain equations? Is it only allowed to have connectors inside connectors, or can we also have records in connectors,
since these are not allowed to have equations either? These questions are not easy to
answer with the current specification, because it is open for interpretation.
Consider Figure 3.3, where an example of the non-terminal for a connector is
listed using a variant of Extended BNF2 . As usual, alternatives are seprated using the ’|’
symbol, and curly brackets ({. . . }) denote that the enclosing elements can be repeated
zero or more times.
2 The following example grammar is not intended to exactly describe the current Modelica specification. The
aim is only to outline the principle of such grammar in order to describe the abstract syntax approach.
3.3 An Abstract Syntax Specification Approach
connector
::=
43
Connector(
{Extends(Cr conM odif ication)}
{DeclCon(modif iability outinner Cd connector)}
{DeclRec(modif iability outinner Rd record)}
{CompCon(conconstraint Cr cd conM odif ication)}
{CompRec(conconstraint Rr rd recM odif ication)}
{CompInt(conconstraint xd )}
{CompReal(conconstraint f lowpref ix yd )}
)
access
::=
Public | Protected
modif iability
::=
Replaceable | Final
outinner
::=
Outer | Inner | OuterInner | NotOuterInner
conconstraint
::=
Input | Output | InputOutput
f lowpref ix
::=
Flow | NonFlow
Figure 3.3: Example of a grammar for the connector non-terminal. Non-terminals
conModification and recModification is not defined in the figure and can be assumed
to define the connector and record modifications respectively.
The grammar is extended with a more abstract notation of metavariables, which range
over names or identifiers. Metavariables Cd and Rd range over identifiers declaring a
new connector respectively record; Cr and Rr range over connector and record names
referencing an already declared connector or record. Metavariables cd , rd , xd , and yd
range over component identifiers having the type of connector, record, Integer, and Real.
All bold strings denote a node in the AST. If the AST is given in a concrete textual
representation, these keywords are used when performing a pre-order traversal of the tree.
In the example, connector can hold zero or many extends nodes, referencing the
meta-variable Cr , denoting all names that reference a declared connector. Hence, using
this meta-variable notation, this rule states that a connector is only allowed to inherit from
another connector.
Furthermore, the example shows that a connector is allowed to have two kinds of
local classes: Connector and Record (nodes DeclCon and DeclRec). CompCon and
CompRec state that a connector can have both connector and record components.
For each of the different kinds of elements, it is stated exactly which prefixes that are
allowed. This description is more restrictive than the concrete syntax, which basically
allows any prefix. In the current specification these restrictions are stated in natural languages, spread out over the specification. For example, on one page it is stated "Variables
declared with the flow type prefix shall be a subtype of Real". Such a text is superfluous
when the grammar for S-AST is specified (note that flowprefix is only available in the
CompReal node).
44
3.4
3 Specifying the Modelica Language
Chapter Summary and Conclusions
In this chapter we have briefly discussed the idea of finding a middle way between an
informal language specification described in natural language and a formal definition.
The main idea is to describe several intermediate languages for the Modelica simulation
process, and to give an abstract syntax for each intermediate language.
We presented the ideas in this chapter in 2007 [24] as an attempt to seek new ways
of improving the Modelica specification. The target audience was the Modelica design
group and others interested in the design of the Modelica language. However, until this
date no further work has been conducted to formalize the specification in this way.
4
Growing the Modelica Language
E
QUATION - BASED OBJECT- ORIENTED (EOO) modeling languages are typically rather
complex. In the hypothetical ideal case, a language can be defined once and subsequently for all future fulfill all demands a user might require regarding expressiveness,
performance, and safety. Unfortunately, this is never the case. Language theory is one of
the core areas within computer science, and history has shown that language design is a
very difficult task and that there is no simple solution to design a language that covers all
problem domains at once. In a famous talk by Guy L. Steele, he discusses the essence of
designing a language for the future [136, 138]:
“If I want to help other persons to write all sorts of programs, should I design
a small programming language or a large one? I stand on this claim: I should
not design a small language, and I should not design a large one. I need to
design a language that can grow. I need to plan ways in which it might grow
- but I need, too, to leave some choices so that other persons can make those
choices at a later time.”
The design space and problems of growing an equation-based object-oriented (EOO)
modeling language have much in common with the design of a general purpose programming language. However, there are also several aspects where EOO languages differ,
raising new questions and design problems.
This chapter discusses and analyzes how EOO languages in general can be designed
for growth, and in particular how this relates to the evolution of the Modelica language.
We do not present any technical contribution, but a systematic categorization of how a
language can grow. The rest of the chapter is organized as follows:
• The design space of how an EOO language can grow is outlined using a new matrix
model that categorizes different ways of growth (Section 4.1).
45
46
4 Growing the Modelica Language
• The trade-offs for different ways of growth are discussed and analyzed from various
stakeholder’ perspective (Section 4.2).
4.1
Different Ways of Growing a Language
A language can grow in many different ways and directions. However, in the end, it is all
about changing the language’s syntax and/or semantics. In this section, we categorize and
exemplify different ways of growing a language.
4.1.1 The Ways of Growth Matrix
The relationship between syntax and semantics regarding language growth is illustrated
in Figure 4.1.
Figure 4.1: Categorization of different ways of growth depending on whether the
language is extended by syntax and/or semantics.
This matrix shows the different ways of growth, whether a language is extended with its
syntax or semantics, both, or none of them. The following sub-sections describe these
ways of growth by giving examples from the Modelica language.
4.1.2 Growth by Adding New Language Features
The most obvious one is given in the upper left corner of Figure 4.1, i.e., extending both
the syntax and the semantics. This is the ordinary way of adding a new language feature,
where the new language construct is added to the syntax grammar and the new semantics
for this construct is defined.
For example, lookup of variables in Modelica can be according to lexical scope and
scope defined by instance hierarchy. The latter was added by defining new syntax where
variables could be defined to be inner or outer. For example, consider Figure 4.2:
Inside model N two instances of model M are created, namely m1 and m2. Besides the
syntactic extension needed for this language feature extension, the meaning of a variable
declared as inner and outer must be defined.
47
4.1 Different Ways of Growing a Language
model M
outer Real x;
...
end M;
model N
inner Real x;
M m1, m2;
...
end N;
Figure 4.2: Example of the rules for using inner/outer.
Both the dynamic and the static semantics must be defined. The dynamic semantics can be seen as the meaning of the actual scoping. From the specification [104], the
definition is:
“An element declared with the prefix outer references an element instance
with the same name but using the prefix inner which is nearest in the enclosing instance hierarchy of the outer element declaration.”
For example, when component m1 is elaborated, it is discovered that x defined in M is
an outer element. Hence, it looks up the variable with same name (in this case x)
nearest in the instance hierarchy, which is the x declared as inner in model N. Hence,
N.x, N.m1.x, and N.m2.x are the same variable. The static semantics define the type
system, e.g., if N.x is an integer but M.x is a real, a conflict exists.
4.1.3 Growth by Adding Syntactic Sugar
Another approach of growing a language is to extend the syntax, but to leave the semantics
as it is (the upper right corner of Figure 4.1). This way of extending a language is often
referred to as adding syntactic sugar. What does this mean?
Basically, the idea is that neither the dynamic nor the static semantics are changed. Instead, only the grammar for the concrete syntax is extended, but not the abstract syntax. A
transformation rule from the new syntax to the abstract syntax is then defined. Hence, the
core of the semantics is left unchanged, but a new syntactic form is added (the syntactic
sugar).
Let us explain the idea with a concrete example. Consider the four Modelica models
M1a, M1b, M1c, and M1d given in Figure 4.3.
All four models state a simple initial value problem, with a slight difference in their definitions. Are all these models stating exactly the same problem, i.e., are the model’s meaning
the same?
The simulation result for the first three models are the same, but model M1d does not
compile. In model M1a and M1c the start attribute states that the initial condition for
x is 5 at time 0. In Modelica specification version 2.0, the procedure for specifying initial
conditions were changed, and the ability to add a initial equation section was
added [93]. Examples M1b and M1d both show that the initial equation x = 5 is used
instead of the start attribute. Hence, the same meaning for initial conditions can be
specified in different syntactic ways. Would it not be possible to just specify the meaning
of one form, and then add the other form as syntactic sugar?
48
4 Growing the Modelica Language
model M1a
Real x(start=5);
equation
der(x) = -x + 2;
end M1a;
model M1b
Real x;
equation
der(x) = -x + 2;
initial equation
x = 5;
end M1b;
model M1c
Real x(start = 5,
fixed=true);
equation
der(x) = -x + 2;
end M1c;
model M1d
Real x(fixed =
true);
equation
der(x) = -x + 2;
initial equation
x = 5;
end M1d;
Figure 4.3: Four almost identical Modelica models stating a simple initial value
problem.
Yes it would be possible, if it was not for the additional special attribute fixed,
which was introduced in the language before the initial conditions. The intuitive meaning
of fixed is that if it is true, then the corresponding start attribute must hold during
the initialization (M1c). This is equivalent to an explicit initial equation (M1b). However,
if fixed is false, the start attribute is treated as a guess value, i.e., the solver can use it
as an initial guess, but it does not need to be the initial value. This is the case in model
M1a because variables in Modelica have as default fixed = false. Why can we not
compile M1d then? The reason is that the attribute fixed does not concern the initial
equation here, but the start attribute. In Modelica, all variables of type real have as
default start = 0. Hence, in the case M1d, the initial condition states that x must be
both equal to 0 and to 5 at the same time, i.e., the initial condition is over-determined and
cannot be solved.
Now, consider Figure 4.4, which shows three potential ways of modeling a steady
state initialization:
Model M2c is using initial equations for modeling the steady state, which is one of
the motivations of introducing initial equations. However, as can be seen in the first two
models, it can also be modeled by using the start attribute together with a new algebraic
variable dx. Models M2b and M2c always give a steady state initialization, but M2a
depends on if the tool chooses to use the start value of dx as initial value (which turned
out to not be the case in the tested Dymola [45] environment).
With the current design of Modelica, it is not trivial to define for example the start
attribute as syntactic sugar of initial equations. However, if it was possible, one can argue
that the meaning of the start attribute would be easier to grasp, both for an end user and
a compiler engineer. As shown in Figure 4.4, it is also possible to define steady state
initialization, by using the start attribute together with ordinary equations.
4.1 Different Ways of Growing a Language
model M2a
Real x;
Real dx(start=0);
equation
der(x) = -x + 2;
der(x) = dx;
end M2a;
49
model M2b
Real x;
Real dx(start=0, fixed=true);
equation
der(x) = -x + 2;
der(x) = dx;
end M2b;
model M2c
Real x;
equation
der(x) = -x + 2;
initial equation
der(x) = 0;
end M2c;
Figure 4.4: Steady state initialization modeled in three different ways.
If initial equations were the basic primitive construct (part of the AST) and the start attribute was added later as syntactic sugar, the language would have grown without changing the semantics. However, as it turned out in the Modelica case, the initial equations
were added afterwards, resulting in that both the semantics and the syntax needed to be
changed.
4.1.4 Growth by New Meanings of Annotations or Built-in
Functions
A somewhat more unusual way to grow a language is to extend the semantics without
changing the syntax (the lower left corner of Figure 4.1). Hence, this approach changes
the meaning of programs without the need to update the grammar for the concrete syntax
of the language. How is this possible?
One way of achieving this has been done in the Modelica language using built-in functions, e.g., sin(x), cos(x), floor(x), delay(expr,delayTime) etc., that all
adhere to the standard function syntax. The semantics of such a functions are informally
described in the specification using natural language. Hence, the semantics is extended
without changing the syntax.
Modelica uses a sophisticated approach for this called annotations. Annotations can
be used for storing various extra information about models, such as graphics, version
information, or documentation.
In the latest specification, a number of annotations are standardized (i.e., the meaning
(semantics) of them are specified). However, vendor tools are free to add their own annotations, as long as the annotations names start with the company’s name. For example,
Figure 4.5 shows an example of a vendor specific graphical annotation:
50
4 Growing the Modelica Language
annotation (
Icon(coordinateSystem(extent={{-100,-100}, {100,100}}),
graphics={__NameOfVendor(Circle(center={0,0}, radius=10))})
);
Figure 4.5: A vendor specific annotation for a circle [103].
4.1.5 Growth by New User Defined Abstractions
The lower right corner of Figure 4.1 assumes that neither the syntax nor the semantics is
extended. How is it then possible to grow the language at all?
This is actually a very fundamental and natural way that has been part of programming
language history from the beginning. The key point is that the user can grow the language
by adding new words and meaning without altering the language definition itself. In a
functional language it is done by defining new functions, in object-oriented languages
by adding class definitions or method definitions to existing classes. In many languages,
these new abstractions can be collected into libraries, enabling reuse at a later time.
In Modelica, the user can grow the set of new user defined abstractions by adding
definitions of functions, classes, models, blocks etc. and then encapsulate them into packages. Hence, growth by new user abstractions is the natural way of programming/modeling, where library developers develop libraries that can later on be reused by other users.
Although this principle is natural and obviously beneficial, it is far from trivial to create a
language that enables this growth.
A key point, also emphasized in Steele’s speech [136], is that new definitions defined
in libraries should look like primitives in the language itself. Hence, in the ideal case,
a user of a language should not be able to distinguish if the language has been extended
with new functionality via a library definition, or by changes in the language specification.
One early programming language that achieved this is LISP [137]. In this language, new
definitions defined by users look like primitives and all primitives look like definitions by
users. Hence, LISP is a language truly built for growth by its users.
4.1.6 Restricting the Language
In the previous sections, four different categories for extending the semantics and/or the
syntax were given. In these scenarios, the language grows by providing more expressiveness, i.e., that new models or programs can be expressed that were not possible before, or
that the same models can be defined in a more concise manner. However, how does a language’s safety aspect grow, i.e., how can the language be improved for detecting errors,
isolating faults in models, and possibly guaranteeing the absence of certain kind of faults
in models?
The safety aspect of a language can actually grow by restricting the language, i.e., by
defining rules that reject models as illegal. This can be defined by restricting the grammar
(the syntax) or by adding semantic rules, e.g., using a static type system to define legal
models (the semantics).
Our previous work on determining over- and under-constrained models by extending
4.2 The Right Way to Grow
51
the static type system of an EOO language [28] is an example of such an approach. Parts
of these ideas have later also been included in the latest Modelica specification [103]. This
is one of the major changes in Modelica version 3.0, where Modelica models are required
to be balanced, i.e., to have the same number of equations as unknowns. A more detailed
overview and rationale of balanced models in Modelica is given by Olsson et. al. [116].
One major implication of growth when restricting the language is backwards compatibility. Unavoidably, models that were earlier legal will become illegal in later language
versions. As long as the illegal models were in fact useless models, e.g., models that
were not possible to simulate, this backwards incompatibility could be acceptable. However, to reject legal working models are of course more controversial. Regarding balanced
models, it has been argued in the Modelica design group, that it is now possible to check
libraries and detect errors earlier and therefore enable the user to build larger models with
less effort.
4.2 The Right Way to Grow
Which is the right way to grow? The right way to grow a modeling or programming
language is not always the easiest way. The easy way is not always easy for everyone. We
will in this section discuss and analyze the benefits and drawbacks of the various ways of
growth from different stakeholders’ perspective.
4.2.1 Stakeholders of an Object-Oriented Equation-Based
Modeling Language
The design and evolution of a language for modeling and analysis of systems is affected
by several different stakeholders:
• Language Designers. Person(s) inventing and designing the actual language.
• End Users. The users who use the language for modeling and analysis. In the
Modelica case, these are usually engineers who create the model mainly using the
graphical component-based drag-and-drop user interface.
• Library Users. Engineers and scientists who develop reusable model libraries. Libraries are created by editing textual Modelica code. The free Modelica standard
library is one example.
• Tool Vendors. Computer scientists and computer engineers who develop the compiler and tools for viewing, editing, compiling, and executing models.
Each of these stakeholders have different demands and priorities regarding what is important when growing the language.
4.2.2 Language Designers’ Perspective
Unfortunately, language designers tend to want their language to be able to handle everything. One of their main challenges is not what to put in the language, but what to actually
52
4 Growing the Modelica Language
leave out. If a language is designed by one person or a small group, these individual(s)
need to judge, test and take all decisions by themselves. This may lead to a concise design,
but there is a considerable risk that important input from other stakeholder’s, such as end
users becomes limited. On the other hand, if the language is designed by a community
with a committee, input comes from many sources. However, there is a substantial risk
that the different parties involved will lead to many compromises that can make the language large and complex. The latter approach with a design community and committee is
the path that the design of Modelica has followed.
When many parties are involved in the language the risk is that new “features” are continuously added to the specification, i.e., the upper left corner of the matrix in Figure 4.1
where both the syntax and semantics are changed. However, if fewer people are involved
in the process, the language may be designed with a more well-defined core semantics
and large parts are defined by using the approach with syntactic sugar. This is the way
that for example Standard ML is defined [98]. This way of defining a language is hard
and challenging, but can if done right lead to a less ambiguous specification. See [24] for
further discussions regarding this topic.
Finally, one of the language designers incentives, that is often forgotten, is the need
for change. If the language is completed, their role is not needed anymore.
4.2.3 End Users’ Perspective
From an end user’s perspective it is of course very important that the language is easy to
use and understand. Moreover, the semantics that the language actually has must be close
to what a fairly new user of the language expects. A clear core semantics is of course beneficial when using syntactic sugar that clearly states similar constructs’ meaning. Hence,
situations as described previously about initial equations in Modelica should if possible
be avoided.
If a user makes mistakes, i.e., creates errors, it is of high importance that the errors
can be detected and that the faults in the model can be isolated and resolved. However, restricting the language so that working models become unusable (i.e., non backwards compatibility) is generally not acceptable. Hence, from an end user’s perspective, language
changes that restrict the language should preferably be done very early in the language’s
history.
End users will of course also be able to solve new problems and use existing models
in different ways. Even though the Modelica language is primarily designed for simulation, there are several other kinds of analysis that are important, such as applications for
automatic control [34] and optimization problems [79].
4.2.4 Library Users’ Perspective
The library user wants expressiveness. In the ideal case, the library user can grow the
language by himself/herself, by adding new functionality which is indistinguishable from
primitive language constructs.
Library users may have conflicting interests with both language designers and tool
vendors because complications and details about the language is not the primary focus for
the user. Hence, library users are typically stakeholders who want to continuously expand
4.3 Chapter Summary and Conclusions
53
and add new complex features into the language, so that it becomes more expressive for
their needs (adding both new syntax and semantics).
4.2.5 Tool Vendors’ Perspective
Tool vendors create tools based on their interpretation of the language specification.
Hence, one of the fundamental needs for a tool vendor is that the specification can be
interpreted unambiguously. The specification must be easy to read, which is the case
for an informal specification written in a natural language. However, it also needs to be
precise and not open for different interpretations.
The approach of using a core semantics and define large parts of the language using syntactic sugar potentially gives a middle way. For example, the built-in edge(b)
operator is defined to be equal to
(b and not pre(b))
Hence, parts that are defined as built-in operators can in fact be treated as syntactic
sugar.
Finally, a perspective that should not be forgotten is the tool vendor’s commercial
perspective. i.e., their focus is primarily their sales possibilities, their customers’ needs,
and making their customers dependent on their tools. This is indicated by the fact that
tool vendors often want to be different compared to their competitors. Hence, this can be
a conflict of interest with the language designers because tool vendors might not always
want to be 100% compatible with competitors.
4.3 Chapter Summary and Conclusions
A programming language in general and an equation-based object-oriented modeling language in particular cannot be designed once and for all. Hence, there is a need to plan for
the language to grow.
We have in this chapter categorized ways of growing a language, by either extending
the semantics and/or the syntax. Moreover, we have listed how different stakeholders have
different perspectives on what is important when growing a language. The importance of
the different ways of growing can be summarized as follows:
• Growth by adding new language features. Always changing both the syntax and the
semantics is the most drastic kind of change of a language and should be minimized
or avoided, especially for mature and widely used languages. The stakeholders
that are most negatively affected of such changes are language designers and tool
vendors, while library users might be the ones that push most for such extensions.
• Growth by adding syntactic sugar. Extending only the syntax by using syntactic
sugar and at the same time keeping a core semantics is one of the preferable approaches to language growth. It gives both a precise language definition for the tool
vendors as well as an understandable language for the user.
• Growth by new meanings of annotations or built-in functions. Growth by only
changing the semantics and not the syntax might first seem to be a very attractive
54
4 Growing the Modelica Language
approach, especially for language designers because few changes are needed in the
specification. However, it can also be dangerous, e.g., in cases where many tool
dependent annotations might make different tools incompatible.
• Growth by new user defined abstractions. Finally, growth by user defined abstractions, i.e., neither the syntax nor the semantics are changed, is the preferable approach in the long term. However, it is far from obvious how to achieve this, especially in such a young language research area as equation-based object-oriented
languages.
5
Types in the Modelica Language
long term goal of modeling and simulation languages is to give engineers the
possibility to discover modeling errors at an early stage, i.e., to discover problems in
the model during design and not after simulation. This kind of verification is traditionally
accomplished by the use of types in the language, where the process of checking for such
errors by the compiler is called type checking. However, the concept of types is often not
very well understood outside parts of the computer science community, which may result
in misunderstandings when designing new languages. Why are then types important?
Types in programming languages serve several important purposes such as naming of
concepts, providing the compiler with information to ensure correct data manipulation,
and enabling data abstraction. Almost all programming or modeling languages provide
some kind of types. However, few language specifications include precise definitions
of types and type systems. This may result in incompatible compilers and unexpected
behavior when using the language.
The purpose of this chapter is twofold. The first part gives an overview of the concept
of types, states concrete definitions, and explains how this relates to the Modelica language. Hence, the first goal is to augment the computer science perspective of language
design among the individuals involved in the Modelica language design. The long-term
objective of this work is to provide aids for further design considerations when developing, enhancing and simplifying the Modelica language. The intended audience is consequently engineers and computer scientists interested in the foundation of the Modelica
language.
The second purpose of this chapter is to study the type concept in Modelica. The main
contribution of this work is the insight that Modelica has two categories of types: class
types and object types. The rest of this chapter is organized as follow:
O
NE
• We outline the concept of types, subtypes, type systems, and inheritance, and how
these concepts are used in Modelica and other mainstream languages (Section 5.1).
55
56
5 Types in the Modelica Language
• We give an overview of the three main forms of polymorphism, and how these
concepts correlate with each other and the Modelica language (Section 5.2).
• We introduce the type concept of Modelica more precisely, where we give a concrete syntax for expressing Modelica types (Section 5.3).
5.1
Types, Subtyping and Inheritance
There exist several models of representing types, where the ideal model [33] is one of the
most well-known. In this model, there is a universe V of all values, containing all values
of integers, real numbers, strings and data structures such as tuples, records and functions.
Here, types are defined as sets of elements of the universe V . There is an infinite number
of types, but all types are not legal types in a programming language. All legal types
holding some specific property, such as being an unsigned integer. Figure 5.1 gives an
example of the universe V and two types: real type and function type, where the latter has
the domain of integer and codomain of boolean.
In most mainstream languages, such as Java and C++, types are explicitly typed by
stating information in the syntax. In other languages, such as Standard ML and Haskell, a
large portion of types can be inferred by the compiler, i.e., the compiler deduces the type
from the context. This process is referred to as type inference and such a language is said
to be implicitly typed. Modelica is an explicitly typed language.
Figure 5.1: Schematic illustration of Universe V .
5.1.1 Language Safety and Type Systems
When a program is executed, or in the Modelica case: during simulation, different kinds
of execution errors can take place. It is practical to distinguish between the following two
types of runtime errors [32].
• Untrapped errors are errors that can go unnoticed and later cause arbitrary behavior
of the system. For example, writing data out of bound of an array might not result
in an immediate error, but the program might crash later during execution.
• Trapped errors are errors that force the computation to stop immediately; for example division by zero. The error can then be handled by the runtime system or by
a language construct, such as exception handling.
A programming language is said to be safe if no untrapped errors are allowed to occur.
These checks can be performed as compile-time checks, also called static checks, where
5.1 Types, Subtyping and Inheritance
57
the compiler finds the potential errors and reports them to the programmer. Some errors,
such as array out of bound errors are hard to resolve statically. Therefore, most languages are also using runtime checks, also called dynamic checking. However, note that
the distinction between compile-time and runtime becomes vaguer when the language is
intended for interpretation.
Typed languages can enforce language safety by making sure that well-typed programs cannot cause type errors. Such a language is often called type safe or strongly
typed . This checking process is called type checking and can be carried out both at runtime and compile-time.
The behavior of the types in a language is expressed in a type system . A type system can be described informally using plain English text, or formally using type rules.
The Modelica language specification is using the former informal approach. Formal type
rules have much in common with logical inference rules, and might at first glance seem
complex, but are fairly straightforward once the basic concepts are understood. Consider
the following:
Γ ⊢ e1 : bool
Γ ⊢ e2 : T
Γ ⊢ e3 : T
(t-if)
Γ ⊢ if e1 then e2 else e3 : T
which illustrates a type rule for the following Modelica if-expression:
if e1 then e2 else e3
A type rule is written using a number of premises located above the horizontal line and
a conclusion below the line. The typing judgement Γ ⊢ e : T means that expression e
has type T with respect to a static typing environment Γ. Hence, the rule (t-if) states that
guard e1 must have the type of a boolean and that e2 and e3 must have the same type,
which is also the resulting type of the if-expression after evaluation. This resulting type
is stated in the last part of the conclusion, i.e., : T .
If the language is described formally, we can attempt to prove the type soundness
theorem [151]. If the theorem holds, the type system is said to be sound and the language type safe or or just safe. The concept of type safety can be illustrated by Robin
Milner’s famous statement "Well-typed programs cannot go wrong" [97]. Modern type
soundness proofs are based on Wright and Felleisen’s approach where type systems are
proven correct together with the language’s operational semantics [151]. Using variant
of this technique, informally stated, type safety holds if and only if the following two
statements hold:
• Preservation - If an expression e has a type T and e evaluates to a value v, then v
also has type T .
• Progress - If an expression e has a type T then either e evaluates to a new expression
e′ or e is a value. This means that a well typed program never gets "stuck", i.e., it
cannot go into a undefined state where no further evaluations are possible.
Note that the above properties of type safety correspond to our previous description of
absence of untrapped errors. For example, if a division by zero error occurs, and the semantics for such event is undefined, the progress property will not hold, i.e., the evaluation
58
5 Types in the Modelica Language
gets "stuck", or enters an undefined state. However, if dynamic semantics are defined for
throwing an exception when the division by zero operation occurs, the progress property
holds.
For the imperative and functional parts of the Modelica language, the safety concept
corresponds to the same methodology as other languages, such as Standard ML. However,
for the instantiation process of models, the correspondence to the progress and preservation properties are not obvious.
Table 5.1 lists a number of programming languages and their properties of being type
safe [32, 99]. The table indicates if the languages are primarily designed to be checked
statically at compile-time or dynamically at runtime. However, the languages stated to be
statically type checked typically still perform some checking at runtime. Although many
of the languages are commonly believed to be safe, few have been formally proven to be
so.
Language
Standard ML
Java
Common LISP
Modelica
C/C++
Assembler
Type Safe
yes
yes
yes
yes
no
no
Checking
static
static
dynamic
static
static
-
Table 5.1: Believed type safety of selected languages.
One can argue whether Modelica is statically or dynamically checked, depending on how
the terms compile-time and runtime are defined. Furthermore, because no exception handling is currently part of the language, semantics for handling dynamic errors such as
array out of bounds is not defined in the language and is therefore considered a compiler
implementation issue. Hence, the Modelica language can only be regarded to be safe if
the tool unconditionally detects all errors and terminates the computation with an error
message.
5.1.2 Subtyping
Subtyping is a fundamental language concept used in most modern programming languages. It means that if a type S has all the properties of another type T , then S can
be safely used in all contexts where type T is expected. This view of subtyping is often
called the principle of safe substitution [124]. In this case, S is said to be a subtype of T ,
which is written as
S <: T
(5.1)
This relation can be described using the following important type rule called the rule of
subsumption.
Γ⊢t:S
S <: T
(t-sub)
Γ⊢t:T
5.1 Types, Subtyping and Inheritance
59
The rule states that if S <: T , then every term 1 t of type S is also a term of type T .
This shows a special form of polymorphism, which we will further explore in Section 5.2.
5.1.3 Inheritance
Inheritance is a fundamental language concept found in basically all class based ObjectOriented (OO) languages. From an existing base class, a new subclass can be created
by extending from the base class, resulting in the subclass inheriting all properties from
the base class. One of the main purposes with inheritance is to save programming and
maintenance efforts of duplicating and reading duplicates of code. Inheritance can in
principle be seen as an implicit code duplication which in some circumstances implies
that the subclass becomes a subtype of the type of the base class.
Figure 5.2 shows an example2 where inheritance is used in Modelica. A model called
Resistor extends a base class TwoPin, which includes two elements v for voltage
and i for current. Furthermore, two instances p and n of connector Pin are public
elements of TwoPin. Because Resistor extends TwoPin, all elements v, i, p and
n are "copied" to class Resistor. In this case, the type of Resistor will also be a
subtype of TwoPin’s type.
connector Pin
SI.Voltage v;
flow SI.Current i;
end Pin;
partial model TwoPin
SI.Voltage v;
SI.Current i;
Pin p, n;
equation
v = p.v - n.v;
0 = p.i + n.i;
i = p.i;
end TwoPin;
model Resistor
extends TwoPin;
parameter SI.Resistance R=100;
equation
R*i = v;
end Resistor;
Figure 5.2: Example of inheritance in Modelica, where a new subclass Resistor
is created by extending the base class TwoPin.
1 The
word term is commonly used in the literature as an interchangeable name for expression.
classes are available in the Modelica Standard Library 2.2, but are slightly modified for reasons of
readability.
2 These
60
5 Types in the Modelica Language
However, a common misunderstanding is that subtyping and inheritance is the same concept [99]. A simple informal distinction is to say that "subtyping is a relation on interfaces", but "inheritance is a relation on implementations". In the resistor example,
not only the public elements v, i, p and n will be part of class Resistor, but also
the meaning of this class, i.e, the equations v = p.v - n.v, 0 = p.i + n.i and
i = p.i.
A famous example, originally stated by Snyder [135], illustrates the difference between subtyping and inheritance. Three common abstract data types for storing data
objects are queue, stack, and dequeue. A queue normally has two operations, insert and
delete, which stores and returns objects in a first-in-first-out (FIFO) manner. A stack has
the same operations, but is using a last-in-first out (LIFO) principle. A dequeue can operate as both a stack and a queue, and is normally implemented as a list, which allows
inserts and removals at both the front and the end of the list.
Figure 5.3 shows two C++ classes modeling the properties of a dequeue and a stack.
Because the class Dequeue implements the properties also needed for a stack, it seems
natural to create a subclass Stack that inherits the implementation from Dequeue. In
C++, it is possible to use so called private inheritance to model inheritance with an exclude operation, i.e., to inherit some, but not all properties of a base class. In the example,
the public methods insFront, delFront, and delRear in class Dequeue are inherited to be private in the subclass Stack. However, by adding new methods insFront
and delFront in class Stack, we have created a subclass, which has the property of a
stack by excluding the method delRear. Stack is obviously a subclass of Dequeue,
class Dequeue{
public:
void insFront(int e);
int delFront();
int delRear();
};
class Stack : private Dequeue{
public:
void insFront(int e)
{Dequeue::insFront(e);}
int delFront()
{return Dequeue::delFront();}
};
Figure 5.3: C++ example, where inheritance does not imply a subtype relationship.
but is it a subtype? The answer is no because an instance of Stack cannot be safely used
when Dequeue is expected. In fact, the opposite is true, i.e., Dequeue is a subtype of
Stack and not the other way around. However, in the following section we will see that
C++ does not treat such a subtype relationship as valid, but the type system of Modelica
would do so.
5.1 Types, Subtyping and Inheritance
61
5.1.4 Structural and Nominal Type Systems
During type checking, regardless if it takes place at compile-time or runtime, the type
checking algorithm must control the relations between types to see if they are correct or
not. Two of the most fundamental relations are subtyping and type equivalence.
Checking of type equivalence is the single most common operation during type checking. For example, in Modelica it is required that the left and right side of the equality in
an equation have the same type, which is shown in the following type rule.
Γ ⊢ e1 : T
Γ ⊢ e2 : T
(t-equ)
Γ ⊢ e1 = e2 : U nit
Note that type equivalence has nothing to do with equivalence of values, e.g., equation
4 = 10 is type correct because integers 4 and 10 are type equivalent. However, this is of
course not a valid equation because the values on the right and left side are not the same.
The Unit type (not to confuse with physical units), shown as the resulting type of the
equation, is often used as a type for uninteresting result values.
A closely related concept to type equivalence is type declaration, i.e., when a type
is declared as a specific name or identifier. For example, the following Modelica record
declaration
record Person
String name;
Integer age;
end Person;
declares a type with name Person. Some languages would treat this as a new unique
type that is not equal to any other type. This is called opaque type declaration. In other
languages, this declaration would simply mean that an alternative name is given to this
type. However, the type can also be expressed by other names or without any name. This
latter concept is commonly referred as transparent type declaration.
In a pure nominal type system, types are compared (subtyping and type equivalence)
by using the names of the declared types, i.e., opaque type declarations are used. Type
equivalence is controlled by checking that the same declared name is used. Furthermore,
the subtype relation in OO languages is checked by validating the inheritance order between classes. The C++ language is mainly using a nominal type system, even if parts of
the language does not obey the strict nominal structure.
Consider the listing in Figure 5.4, which illustrates a C++ model similar to the resistor example earlier given as Modelica code in Figure 5.2. In this case, Resistor is a
subclass of TwoPin and the type of Resistor is therefore also a subtype of TwoPin’s
type. However, the type of Inductor is not a subtype to the type of TwoPin because
Inductor does not inherit from TwoPin. Moreover, Resistor2 is not type equivalent to Resistor even if they have the same structure and inherit from the same base
class because they are opaquely declared.
In a structural type system [124], declarations are introducing new names for type
expressions, but no new types are created. Type equivalence and subtype relationship is
only decided depending on the structure of the type, not the naming.
The Modelica language is inspired by the type system described by Abadi and Cardelli
[2] and is using transparent type declarations, i.e., Modelica has a structural type system.
62
5 Types in the Modelica Language
class Pin{
public:
float v, i;
};
class TwoPin{
public:
TwoPin() : v(0),i(0){};
float v, i;
Pin p, n;
};
class Resistor : public TwoPin{
public:
Resistor() : r(100) {};
float r;
};
class Resistor2 : public TwoPin{
public:
Resistor2() : r(200) {};
float r;
};
class Inductor{
public:
Inductor() : v(0),i(0){};
float v, i;
Pin p, n;
const float L;
};
Figure 5.4: Resistor inheritance example in C++.
Consider the Resistor example given in Figure 5.2 and the two complementary models Inductor and Resistor2 in Figure 5.5. Here, the same relations hold between
TwoPin and Resistor, i.e., the type of Resistor is a subtype of TwoPin’s type.
The same holds between TwoPin and Resistor2. However, now Resistor and
Resistor2 are type equivalent because they have the same structure and naming of
their public elements. Furthermore, the type of Inductor is now a valid subtype of
TwoPin’s type because Inductor contains all public elements (type and name) of the
ones available in TwoPin.
It is important to stress that classes and types in a structural type system are not the
same thing, which also holds for Modelica. The type of a class represents the interface of
the class relevant to the language’s type rules. The type does not include implementation
details, such as equations and algorithms.
Note that a nominal type system is more restrictive than a structural type system,
5.2 Polymorphism
63
model Resistor2
extends TwoPin;
parameter SI.Resistance R=200;
equation
R*i = v;
end Resistor;
model Inductor
Pin p, n;
SI.Voltage v;
SI.Current i;
parameter SI.Inductance L=1;
equation
L*der(i) = v;
end Inductor;
Figure 5.5: Complementary Inductor and Resistor2 models to the example
in Figure 5.2.
i.e., two types that have a structured subtype relation can always have a subtype relation
by names (if the language’s semantics allows it). However, the opposite is not always
true. Recall the Dequeue example listed in Figure 5.3. The class Stack has a subclass
relation to Dequeue, but a subtype relation cannot be enforced, due to the structure of
the class. The converse could be true, but the type system of C++ would not allow it
because it is nominal and subtype relationships are based on names. Hence, a structural
type system can be seen as more expressive and flexible compared to a nominal one, even
if both gives the same level of language type safety.
5.2 Polymorphism
A type system can be monomorphic in which each value can belong to at most one type. A
type system, as illustrated in Figure 5.1, consisting of the distinct types function, integer,
real, and boolean is a monomorphic type system. Conversely, in a polymorphic type system, each value can belong to many different types. Languages supporting polymorphism
are in general more expressive compared to languages only supporting monomorphic
types. The concept of polymorphism can be handled in various forms and have different
naming depending on the paradigm where it is used. Following John C. Mitchell’s categorization, polymorphism can be divided into the following three main categories [99]:
• Subtype Polymorphism
• Parametric Polymorphism
• Ad-hoc Polymorphism
64
5 Types in the Modelica Language
There are other similar categorizations, such as given by Cardelli and Wegner’s [33],
where the ad-hoc category is divided into overloading and coercion at the top level of
categories.
5.2.1 Subtype Polymorphism
Subtyping is an obvious way that gives polymorphic behavior in a language. For example,
an instance of Resistor can be represented both as a TwoPin type and a Resistor
type. This statement can also be shown according to the rule of subsumption (t-sub)
described in Section 5.1.2.
When a value is changed from one type to some supertype, it is said to be an up-cast.
Up-casts can be viewed as a form of abstraction or information hiding , where parts of the
value becomes invisible to the context. For example, an up-cast from Resistor’s type
to TwoPin’s type hides the parameter R. Up-casts are always type safe, i.e., the runtime
behavior cannot change due to the upcast.
However, for subtype polymorphism to be useful, typically types should be possible
to down-cast, i.e., to change to a subtype of a type’s value. Consider function Foo
function Foo
input TwoPin x;
output TwoPin y;
end Foo;
where we assume that down-casting is allowed3 . It is in this case valid to pass either a
value of type TwoPin (type equivalence) or a subtype to the type of TwoPin. Regardless
if a value of TwoPin’s or Inductor’s type is sent as input to the function, a value of
TwoPin’s type will be returned. It is not possible for the static type system to know if this
is a TwoPin, Resistor or a Inductor type. However, for the user of the function, it
might be crucial to handle it as an Inductor, which is why a down-cast is necessary.
Down-casting is however not a safe operation because it might cast down to the wrong
subtype. In Java [65], before version 1.5 when generics were introduced, this safety
issue could only be handled using dynamic checks and raising dynamic exceptions if an
illegal down-cast was made. Subtype polymorphism is sometimes called "poor-man’s
polymorphism" because it enables polymorphic behavior, but the safety of down-casts
must be handled dynamically [124].
The Modelica language supports subtyping as explained previously, but does not have
any operation for down-cast. Because the language does not include this unsafe operation,
only a limited form of subtype polymorphism can be used with functions. For example, a
function can operate on a polymorphic type as input, such as TwoPin, but it only makes
sense to return values of a type that can be directly used by the caller.
However, subtype polymorphism is more extensively used when reusing and replacing
components in models, i.e., by using the redeclare keyword.
3 This function type or example is not valid in the current Modelica standard. It is used only for the purpose
of demonstrating subtype polymorphism.
5.2 Polymorphism
65
5.2.2 Parametric Polymorphism
The term parametric polymorphism means that functions or classes can have type parameters, to which types or type expressions can be supplied. The term parametric polymorphism is often used in functional language communities, while people related to objectoriented languages tend to use the term generics.
The C++ template mechanism is an example of explicit parametric polymorphism,
where the type parameter must be explicitly declared. Consider for example Figure 5.6,
where a template function swap is implemented. The type parameter T must be explicitly
stated when declaring the function. However, the type argument is not needed when calling the function, e.g., both int x,y; swap(x,y); and float i,j; swap(i,j)
are valid uses of the function.
template<typename T>
void swap(T& x, T& y){
T tmp = x;
x = y;
y = tmp;
}
Figure 5.6: Explicit parametric polymorphism in C++.
Standard ML on the other hand is making use of implicit parametric polymorphism, where
the type parameters do not need to be explicitly stated when declaring the function. Instead, the type inference algorithm computes when type parameters are needed.
A notable difference of parametric and subtype polymorphism is that all type checking
of parametric polymorphism can take place at compile-time and no unsafe down-cast
operation is needed.
Standard ML and and C++ are internally handling parametric polymorphism quite
differently. In C++ templates, instantiation to compiled code of a function is done at
link time. If for example function swap is called both using int and float, different
code for implementations and calls of the function is generated for the two function calls.
Standard ML on the other hand is using a uniform data representation, where all data
objects are represented internally as pointers/references to objects. Therefore, there is no
need to create different copies of code for different types of arguments.
Modelica can be seen to support a variant of parametric polymorphism, by using the
redeclare construct on class declarations.
5.2.3 Ad-hoc Polymorphism
In parametric polymorphism the purpose is to declare one implementation that can be
used with different types of arguments. Ad-hoc polymorphism, by contrast, allows a
polymorphic value to be used differently depending on which type the value is viewed to
have.
There are several language concepts that fall under the concept of ad-hoc polymorphism [33], where Overloading and Coercion are most notable. Other related concepts
66
5 Types in the Modelica Language
that also fall under this category are Java’s instanceOf concept and different form of
pattern matching [124].
Overloading
A symbol is overloaded if it has two or more meanings, which are distinguished by using
types. That is, a single function symbol or identifier is associated with several implementations.
An example of overloading that exists in many programming languages is operator
overloading for built in types. For example, the symbol + is using infix notation and has
two operands associated with it. The type of these operands decides how the operation
should be carried out, i.e., which implementation should be used.
Overloading can take place at either compile-time or at runtime. Overloading used at
runtime is often referred to as dynamic lookup [99], dynamic dispatch or multi-method
dispatch. In most cases, the single term overloading refers to static overloading taking
place at compile-time. The distinction becomes of course vague, if the language is interpreted and not compiled.
Another form of overloading available in some languages is user-defined function
overloading, where a function identifier can represent several implementations for different type arguments. Modelica is currently not supporting any form of user defined
overloading.
Coercion
Another form of ad-hoc polymorphism is coercion or implicit type conversion, which is
runtime conversion between types, typically performed by code automatically inserted by
the compiler. The distinction between overloading and type coercion is not always clear,
and the two concepts are strongly related. Consider the following four expressions of
multiplication [33]:
7
6.0
6
6.0
*
*
*
*
9
9.1
5.2
8
//Integer * Integer
//Real * Real
//Integer * Real
//Real * Integer
All four of these expressions are valid Modelica expressions, but they can in the context
of coercion and overloading be interpreted in three different ways:
• The multiplication operator is overloaded four times, one for each of the four expressions.
• The operator is overloaded twice; one for each of the the first two expressions. If
the arguments have different types, i.e., one is Real and the other one Integer,
type coercion is first performed to convert the arguments to Real.
• Arguments are always implicitly converted to Real, and the operator is only defined for Reals.
5.3 Modelica Types
67
Type conversions can also be made explicit, i.e., code is inserted manually by the programmer that converts the expression to the correct type.
In Modelica, implicit type conversion is used when converting from Integer to
Real. Of the three different cases listed above, the second one applies to the current
Modelica 3.2 standard.
5.3 Modelica Types
In the previous sections we described different aspects of types for various languages. In
this section we will present a concrete syntax for describing Modelica types, followed by
rules stating legal type expressions for the language.
The current Modelica language specification [104] specifies a formal syntax of the
language, but the semantics including the type system are given informally using plain
English. There is no explicit definition of the type system, but an implicit description
can be derived by reading the text describing relations between types and classes in the
Modelica specification. This kind of implicit specification makes the actual specification
open for interpretation, which may result in incompatible compilers; both between each
other, but also to the specification itself. Our work in this section should be seen as a first
step to formalize what a type in Modelica actually is. Previous work has been performed
to formally specify the semantics of the language [85]. The formal specification of the
semantics includes the meaning of a Modelica type. However, the earlier work was not as
precise as a distinction between class type and object type was not made.
Why is it then so important to have a precise definition of the types in a language? As
we have described earlier, a type can be seen as an interface to a class or an object. The
concept of interfaces forms the basis for the widely accepted approach of separating specification from implementation, which is particularly important in large scale development
projects. To put it in a Modelica modeling context, let us consider a modeling project of
a car, where different modeling teams are working on the wheels, gearbox and the engine. Each team has committed to provide a set of specific attributes for their component,
which specifies the interface. The contract between the teams is not violated, as long
as the individual teams are following this commitment of interface (the specification) by
adding / removing equations (the implementation). Because the types state the interfaces
in a language with a structural type system, such as Modelica, it is obviously decisive that
they have a precise definition.
Our aim here is to define a precise notation of types for a subset of the Modelica
language, which can then further be extended to the whole language. Because the Modelica language specification is open for interpretation, the presented type definition is our
interpretation of the specification.
5.3.1 Class Types and Object Types
Now, let us study the types of some concrete Modelica models. Consider the following
model B, which is rather uninteresting from a physical point of view, but demonstrates
some key concepts regarding types.
68
5 Types in the Modelica Language
model B
parameter Real s=-0.5;
connector C
flow Real p;
Real q;
end C;
protected
Real x(start=1);
equation
der(x) = s*x;
end B;
What is the type of model B? Furthermore, if B was used and instantiated as a component in another model, e.g., B b;, what would the resulting type for element b be?
Would the type for B and b be the same? The answer to the last question is definitely no.
Consider the following listing, which illustrates the type of model B.
model classtype //Class type of model B
public parameter Real objtype s;
public connector classtype
flow Real objtype p;
nonflow Real objtype q;
end C;
protected Real objtype x;
end
This type listing follows the grammar syntax listed in Figure 5.7. The first thing to
notice is that the name of model B is not visible in the type. Recall that Modelica is using a
structural type system, where the types are determined by the structure and not the names,
i.e., the type of model B has nothing to do with the name B. However, the names of the
elements in a type are part of the type, as we can see for parameter s and variable x.
The second thing to observe is that the equation part of the model is missing in the
type definition. The reason for this is that equations and algorithms are part of the implementation and not the model interface. Moreover, all elements s, C and x are preserved
in the type, but the keywords model, connector and basic type Real are followed
by new keywords classtype or objtype. This is one of the most important observations to make regarding types in a class based system using structural subtyping and
type equivalence. As we can see in the example, the type of model B is a class type, but
parameter s is an object type. Simply stated: A class type is the type of one of Modelica’s
restricted classes, such as model, connector, record etc., but an object type is the
type of an instance of a class, i.e., an object. Now, the following shows the object type of
b, where b represents an instance of model B:
5.3 Modelica Types
69
model objtype //Object type of b
parameter Real objtype s;
end
Obviously, both the type of connector C and variable x have been removed from the
type of b. The reason is that an object is a runtime entity, where neither local classes
(connector C) nor protected elements (variable x) are accessible from outside the instance.
However, note that this is not the same as that variable x does not exist in a instance of B;
it only means that it is not visible to the outside world.
Now, the following basic distinctions can be made between class types and object
types :
• Classes can inherit (using extends) from class types, i.e., the type that is bound to
the name used in an extends clause must be a class type and not an object type.
• Class types can contain both object types and class types, but object types can only
hold other object types.
• Class types can contain types of protected elements; object types cannot.
• Class types are used for compile time evaluation, such as inheritance and redeclarations.
Let us now take a closer look at the grammar listed in Figure 5.7. The root non-terminal
of the grammar is type, which can form a class or object type of the restricted classes
or the built in types Real, Integer, Boolean, String, or enumeration. The
grammar is given using a variant of Extended Backus-Naur Form (EBNF), where terms
enclosed in brackets {} denote zero, one or more repetitions. Keywords appearing in the
concrete syntax are given in bold font. All prefixes, such as public, flow, outer etc.
can be given infinitely many times. The correct use of these prefixes is not enforced by
the grammar, and must therefore be handled later in the semantic analysis. We will give
guidelines for default prefixes and restrictions of the use of prefixes in the next subsection.
Now, let us introduce another model A, which extends model B:
model A
extends B(s=4);
C c1;
equation
c1.q = -10*der(x);
end A;
The question is now what the type of model A is and if it is instantiated to an object,
i.e., A a;, what is then the type of a? The following shows the type of model A.
70
5 Types in the Modelica Language
model classtype //Class type of A
public parameter Real objtype s;
public connector classtype
flow Real objtype p;
nonflow Real objtype q;
end C;
public connector objtype
flow Real objtype p;
nonflow Real objtype q;
end c1;
protected Real objtype x;
end
First of all, we see that the type of model A does not include any extends keyword
referring to the inherited model B. Because Modelica has a structural type system, it is
the structure that is interesting, and thus a type only contains the collapsed structure of
type
::=
(model | record | connector |
block | function | package)
kindof type
{{pref ix} type identif ier ;} end
|
(Real | Integer | Boolean |
String) kindof type
|
enumeration kindof type
enumlist
kindof type
::=
classtype | objtype
pref ix
::=
access | causality |
f lowpref ix | modif iability |
variability | outerinner
enumlist
::=
( identif ier {, identif ier} )
access
::=
public | protected
causality
::=
input | output |
f lowpref ix
::=
flow | nonflow
modif iability
::=
replaceable | modifiable |
inputoutput
final
variability
::=
constant | parameter |
discrete | continuous
outerinner
::=
outer | inner |
notouterinner
Figure 5.7: Concrete syntax of partial Modelica types.
5.3 Modelica Types
71
inherited elements. Furthermore, we can see that the protected elements from B are still
available, i.e., inheritance preserves the protected element after inheritance. Moreover,
because model A contains an instance of connector C, this is now available as an object
type for element c1 in the class type of A. Finally, consider the type of an instance a of
class A:
model objtype //Object type of a
parameter Real objtype s;
connector objtype
flow Real objtype p;
nonflow Real objtype q;
end c1;
end
The protected element is now gone, along with the elements representing class types.
A careful reader might have noticed that each type definition ends without a semi-colon,
but elements defined inside a type such as model classtype ends with a semi-colon.
A closer look at the grammar should make it clear that types themselves do not have
names, but when part of an element definition, the type is followed by a name and a semicolon. If type expressions were to be ended with a semi-colon, this recursive form of
defining concrete types would not be possible.
5.3.2 Prefixes in Types
Elements of a Modelica class can be prefixed with different notations, such as public,
outer or replaceable. We do not intend to describe the semantics of these prefixes
here, instead we refer to the specification [102] and to the more accessible description
by Fritzson [51]. Most of the Modelica language’s prefixes have been introduced in the
grammar in Figure 5.7. However, not all prefixes are allowed or have any semantic meaning in all contexts.
In this subsection, we present a partial definition of when different prefixes are allowed
to appear in a type. In currently available tools for Modelica, such as Dymola [45] and
OpenModelica [52], the enforcement of these restrictions is sparse. The reason for this
can both be the difficulties to extract this information from the specification and the fact
that the rules for the type prefixes are very complex.
In Figure 5.8 several abbreviations are listed. The lower case abbreviations a, c, c′
etc. define sets of prefixes. The uppercase abbreviations M , R etc. together with a
subscription of c for class type and o for object type, represents the type of an element
part of another type. For example Mc is a model class type, and Ro is a record object
type.
Now, consider the rules for allowed prefixes of elements shown in the tables given in
Figure 5.9, Figure 5.10, and Figure 5.11.
In Figure 5.9 the intersection between the column (the type of an element) and the
row (the type that contains this element) states the allowed prefixes for this particular
element. This table shows which prefixes are allowed for a class type that is part of
another class type. For example, recall the connector C in model A. When looking at the
type of A, we have a class type (the model class type) that contains another class type (the
connector class type), i.e., the allowed prefixes are given in the intersection of row 1 and
72
5 Types in the Modelica Language
M=
R =
C =
B =
F =
P =
X=
Y
a
a′
c
=
=
=
=
c′ =
f =
m=
m′ =
v =
v′ =
v ′′ =
o =
model
record
connector
block
function
package
Integer, Boolean,
enumeration, String
Real
{public, protected}
{public}
{input, output,
inputoutput}
{input, output}
{flow, nonflow}
{replaceable,
modifiable, final}
{modifiable, final}
{constant, parameter
discrete, continuous}
{constant, parameter
discrete}
{constant}
{outer, inner,
notouterinner}
Access
Causality
Flowprefix
Modifiability
Variability
Outerinner
Figure 5.8: Abbreviation for describing allowed prefixes. Default prefixes are underlined.
Mc Rc
Cc
Mc amo amo amo
Rc .
.
.
.
.
Cc .
Bc amo amo amo
Fc .
am .
Pc am amv ′′ am
Bc
amo
.
.
amo
.
am
Fc
amo
.
.
amo
am
am
Pc
.
.
.
.
.
a′ m
Xc
amo
.
.
amo
am
am
Yc
amo
.
.
amo
am
am
Figure 5.9: Prefixes allowed for elements of class type (columns) inside a class type
(rows).
column 3. In this case, access prefixes public and protected, modifiability prefixes
replaceable, modifiable, and final, and outer/inner prefixes outer, inner
and notouterinner are allowed.
We have introduced a number of new prefixes: inputoutput, notouterinner,
nonflow, modifiable, and continuous. These new prefixes are introduced to
enable a complete type definition, e.g., it should be possible to explicitly specify that a
variable in a connector is not a flow variable by giving a nonflow prefix. However, for
simplicity, sometimes it is more convenient to leave out some of the prefixes, and instead
73
5.3 Modelica Types
Mc
Rc
Cc
Bc
Fc
Pc
Mo
amo
.
.
amo
.
.
Ro
Co
Bo
acmo acmo amo
mo
.
.
mo
mo
.
ac′ mo ac′ mo amo
ac′ m .
.
amv ′′ .
.
Fo
amo
.
.
amo
am
.
Po
.
.
.
.
.
.
Xo
acmv ′ o
mv ′ o
m
ac′ mv ′ o
ac′ mv ′
amv ′′
Yo
acmvo
mvo
mcf vo
ac′ mvo
ac′ mv
amv ′′
Figure 5.10: Prefixes allowed for elements of object type (columns) inside a class
type (rows).
Mo
Ro
Co
Bo
Fo
Po
Mo
o
.
.
o
.
.
Ro
cm′ o
m′ o
m′ o
c′ o
c′
.
Co
co
.
o
c′ o
.
.
Bo
o
.
.
o
.
.
Fo
o
.
.
o
.
.
Po Xo
Yo
.
cm′ v ′ o cm′ vo
.
m′ v ′ o m′ vo
.
.
cf m′ vo
.
c′ m′ v ′ o c′ m′ vo
.
m′ v ′
m′ v
.
.
.
Figure 5.11: Prefixes allowed for elements of object type (columns) inside an object
type (rows).
use default prefixes. The defined default prefixes are shown underlined in Figure 5.8. If
no underlined prefix exists in a specific set, this implies that the prefix must be explicitly
stated.
Analogously to the description of Figure 5.9, Figure 5.10 shows the allowed prefixes
for elements of object types contained in a class type and Figure 5.11 shows object types
contained in object types. There are no tables given for class types contained in object
types for the simple reason that object types are not allowed to contain class types.
In some of the cells in the tables described above, a dot symbol is shown. This means
that the specific type of element inside a certain type is not allowed. Hence, such a
combination should not be allowed by the compiler at compile-time.
Now, let us observe some general trends between the allowed attributes. First of all,
object types cannot contain class types, which is why there are only 3 tables. Secondly,
access prefixes (public, protected) are only allowed in class types, which is why
Figure 5.11 does not contain any abbreviation a. Thirdly, the replaceable prefix
does not make sense in object types because redeclarations may only occur during object
creation or inheritance, i.e., compile-time evaluation. Then when an object exists, the type
information for replaceable is of no interest any more. Finally, we can see that package
class types can hold any other class types, but no other class type can hold package types.
Note that several aspects described here are our design suggestions for simplifying
and making the language more stringent from a type perspective. Currently, there are no
limitations for any class to contain packages in the Modelica specification. Furthermore,
there are no strict distinctions between object- and class types because elaboration and
type checking are not clearly distinguished. Hence, redeclaration of elements in an object
are in fact possible according to the current specification, even if it does not make sense
in a class based type perspective.
74
5 Types in the Modelica Language
5.3.3 Completeness of the Type Syntax
One might ask if this type definition is complete and includes all aspects of the Modelica
language and the answer to that question is no. There are several aspects, such as arrays,
partial and encapsulated classes, units, constrained types, conditional components and
external functions that are left out on purpose.
The main reason for this work is to pinpoint the main structure of types in Modelica,
not to formulate a complete type definition. As we can see from the previous sections,
the type concept in the language is very complex and hard to define, due to the large
number of exceptions and the informal description of the semantics and type system in
the language specification.
The completeness and correctness of the allowed type prefixes described in the previous section depend on how the specification is interpreted. However, the notation and
structure of the concrete type syntax should be consistent and is intended to form the basis
for incorporating this improved type concept tighter into the language.
Finally, we would like to stress that defining types of a language should be done in
parallel with the definition of precise semantic and type rules. Because the latter information is currently not available, the precise type definition is obviously not possible to
validate.
5.4
Chapter Summary and Conclusions
We have in this chapter given a brief overview of the concept of types and how they relate
to the Modelica language. The first part of the Chapter described types in general, and the
latter sections detailed a syntax definition of how types can be expressed for the Modelica
language.
6
Over- and Under-Constrained
Systems of Equations
model in an EOO language needs to have the same number of equations as unknowns. This chapter describes a novel technique to determine over- and underconstrained systems of equations in models, based on a concept called structural constraint delta , denoted C∆ . Our approach makes use of static type checking and consists
of a type checking algorithm, which determines if a model is under- or over-constrained
without elaborating its subcomponents. This is essential if separate compilation of components is introduced in an EOO language. Furthermore, the concept also allows detection
of constraint-errors at the subcomponent level and improves the possibilities of isolating
the source of the errors. We have implemented it for a subset of the Modelica language,
and successfully validated it on several examples. However, the idea is not limited to
Modelica and should be possible to generalize to other EOO languages. The remainder
of this chapter is structured as follows.
A
• We describe the problem and motivation for determining over- and under-constrained
systems of equations (Section 6.1).
• We introduces a minimal EOO language called Featherweight Modelica (FM), its
syntax and informal description of semantics and type system (Section 6.2).
• We define the concept of structural constraint delta, the algorithms used for constraint checking and debugging, and how these concepts fit into the FM language’s
type system (Section 6.3).
• We describe how we validate the approach by making use of a prototype implementation (Section 6.4).
The work of this chapter was published in 2006 [28]. Later revisions of the Modelica
specification (version 3.0 released in 2007 [103]) included a similar concept with balanced
models.
75
76
6 Over- and Under-Constrained Systems of Equations
6.1
Problem and Motivation
While EOO languages provide attractive advantages, they also present new challenges in
the areas of static analysis, type systems, and debugging. This chapter deals with specific
problems arising with EOO languages in two areas:
• Constraint checking of separately compiled components.
• Error detection and debugging.
The continuous-time behavior of a EOO model is typically described by a DAE. The existence of a unique solution requires that the number of equations and variables (unknowns)
are equal1 . If the number of equations is greater than unknowns, the model is said to be
over-constrained . Conversely, if the number of unknowns is greater than equations, it is
under-constrained .
In an EOO model, variables and equations can be specified in different subcomponents
of the model. To find out if a model has the same number of equations as variables, the
model has traditionally been elaborated into a flat system of equations, where the number
of variables and equations can be counted. However, this simple counting approach is
not possible in the general case when one or more components in the model have been
separately compiled.
Figure 6.1 outlines a potential architecture for separate compilation of Modelica models. Because symbolic transformation always needs to take into account the whole equation system, it is performed after the linking phase. Consider a simple model of a car,
consisting of axis, gearbox, and an engine. In order to find out if the car model has the
same number of equations as unknowns, we have to translate it into one large system of
equations and count the number of variables and equations in that system. In the simple
case the compiled engine always generate the same set of equations. However, models can also typically be parameterized with other models (using for example Modelica’s
redeclare-construct), resulting in that a separately compiled model can not always
result in a flat DAE2 .
Moreover, if a model intended for simulation has not the same number of equations
as variables, it is an error. This can be detected (trivially) after compiling the model into a
system of equations. However, it is non-trival to isolate the fault of the error, i.e., to help
the user to pinpoint where or which components the error is located in. Consider again the
car model discussed above. When the model is compiled (translated into equations), the
user might be presented with an error message such as: “There are 20237 equations and
20235 variables”. Debugging the car model with only this message and a listing of equations and variables is extremely hard. There exist software tools [45] and methods [29]
that help the user in this process, but they require information of the model’s whole system
of equations, i.e., the tools need the flat hybrid DAE.
1 This means that the incidence matrix associated with the system of equations is square, which is a necessary
but not sufficient condition for the equation system to be structurally non-singular.
2 In this thesis, we do not make any statement on how to handle the problem of separate compilation. We
will only argue for that our approach can enable static checking of separately compiled models.
6.2 Featherweight Modelica
77
Figure 6.1: Separate compilation in Modelica.
To summarize, there are two deficiencies with the current practice in the Modelica compilers before Modelica 3.03 that we would like to stress.
1. Complete elaboration of all elements in a model is required to determine if the
model is under- or over-constrained.
2. If the model turns out to be under- or over-constrained, it is very hard to find the
bug because the error is detected at the level of flat system of equations rather than
at a component/model level.
6.2 Featherweight Modelica
Modelica is a large and complex language that includes many concepts such as discrete
simulation, algorithm sections, and functions, which are not central for our purpose. Consequently, we have designed and extracted a subset of the Modelica language, which
models important aspects of the continuous and object-oriented parts of the language. We
call this language Featherweight Modelica (FM). This section will informally present the
language.
3 The
approach presented in this chapter was published in 2006, i.e., before Modelica 3.0 was released.
78
6 Over- and Under-Constrained Systems of Equations
6.2.1 Syntax and Semantics
A model designed in FM can express continuous behavior by using Differential Algebraic
Equations (DAEs). Reuse is achieved by the extends and redeclare constructs.
In Figure 6.2 the syntax grammar of FM is listed using a variant of extended BackusNaur Form (EBNF). Alternatives are separated using the ’|’ symbol, optional arguments
are given using square brackets ([· · · ]) and the curly brackets ({· · · }) denote that the
enclosed elements can be repeated zero or more times. Terminals are highlighted in boldface.
The non-terminal root gives the starting point of a model definition. The metavariable
M ranges over names of models and m over names of instances of models; C ranges over
names of connectors and c over names of instances of connectors; R ranges over names
of records and r over names of instances of records; x ranges over variable names of type
Real. Note that numeric subscripts are used to differentiate between meta-variables. All
bold strings are keywords in the language except for Real, which is the built in type for
R.
The foundation of the language is the class concept, where model, connector, and
record are special forms of classes. By observing the grammar, we can see that only
models are allowed to have connections or to contain elements that can be redeclared or
modified. Connectors are the only classes whose instances can be part of a connectequation, while Real types and record instances can be part of equations. Note that
this can be seen in the grammar by considering the meta-variables.
There are two kinds of prefixes: access and modifiability. Access prefixes state if an
element in a model can be defined to be public or protected. The latter is only visible outside the model by a model extending from the class. The second prefix category is
modifiability, defining how an element can be modified. Declaring an element replaceable
makes it possible for a user to redeclare the element. Setting the prefix of an element to
final means that the element can neither be modified nor redeclared. Only models can
be redeclared and only Reals can be modified in FM.
6.2.2 Type-Equivalence and Subtyping
Modelica is using a so called structural type system [124], where the type of a class is
determined by the structure of its components. However, other object-oriented languages,
such as Java, are using primarily a nominal type system, where the name of a declared
class identifies its type.
The Modelica language specification [102] is informally describing the semantics and
type system of the language. From the specification, the following definition of type
equivalence can be extracted:
Definition 6.2.1 (Type Equivalence). Two types T and U are equivalent if T and U
denote the same built-in type, or T and U are types of classes, T and U contain the same
public declaration elements (according to their names), and the elements’ types in T are
equivalent to the corresponding element types in U.
Note that a class C is not the same as the type of class C because the type only represents
the interface of the class and not the private implementation or semantic part, such as
equations.
79
6.2 Featherweight Modelica
root
::=
{model | connector | record}
model
::=
model M1
{extends M2 [modif ication] ;}
{[access] [modif iability]
(M3 m [modif ication] |
C c | R r | Real x [= lnum]) ;}
[equation {equation;}]
end M1 ;
connector
::=
connector C1 {extends C2 ;}
{[flow] Real x ;}
end C1 ;
record
::=
record R1 {extends R2 ;}
{(R3 r | Real x) ;}
end R1 ;
modif ication
::=
(modif ication′ {, modif ication′ })
modif ication′
::=
redeclare M m [modif ication]
|
x = lnum
access
::=
public | protected
modif iability
::=
replaceable | modifiable
equation
::=
connect(c1 ,c2 ) | e1 = e2
e
::=
|
e1 + e2 | e1 - e2 | e1 * e2 | e1 / e2
-e | ( e ) | lnum | der(x) | x | r
|
time | sin(e)
|
final
Figure 6.2: Syntax of Featherweight Modelica.
Besides type equivalence, the Modelica language defines subtyping relationships between types of classes.
Definition 6.2.2 (Subtyping). For any types S and C, S is a supertype of C and C is
a subtype of S if they are equivalent or if: every public declaration element of S also
exists in C (according to their names) and those element types in S are supertypes of the
corresponding element types in C.
In the following text, we will use the notation of C <: S, meaning that the type of class
C is a subtype of the class S’s type.
Now, consider the three models given in Figure 6.3. According to Definition 6.2.2,
we can see that B <: A because the public elements p and c that exist in A also exist
in B. We can see that C extends A, i.e., C inherits all components and equations from A.
Furthermore, C defines an element q, which makes C <: A. In addition because both B
80
6 Over- and Under-Constrained Systems of Equations
model A
Real p;
Real c;
equation
c = 2;
der(p) = -c*p;
end A;
model B
Real p;
Real c;
Real q;
equation
c = 2;
der(p) = -c*p;
end B;
model C
extends A;
Real q;
equation
q = p*p;
end C;
Figure 6.3: Three different Modelica models.
and C hold the same public elements, it can be concluded from Definition 6.2.1 that B and
C are type equivalent.
Subtyping is a fundamental concept in many programming languages. Generally, it
means that if a type S has all the properties of another type T , then S can be safely used in
all contexts where type T is expected. This view of subtyping is often called the principle
of safe substitution [124]. Now the question arise if this is true for the type system and
examples described above. The main question is what we mean by safe substitution in the
context of equation-based object-oriented languages. If we count the number of variables
and equations in each of the models in Figure 6.3, we can see that model A has 2 variables
and 2 equations, model B has 3 variables and 2 equations and finally model C has 3
variables and 3 equations. In the current type system of Modelica, both B and C are said
to be safe replacements of A. However, in this case we know that replacing A with C gives
us a potentially solvable system with 3 variables and 3 equations, but replacing A with B
results in a under-constrained system with 3 variables and 2 equations, which will not give
a unique solution. Can we after these observations still regard B as a safe replacement of
A? We think not, and will in the next subsections propose a solution.
6.3
The Approach of Structural Constraint Delta
In this section, we will present an approach that addresses the problem of determining
under- and over-constrained components without performing complete elaboration. We
start by giving a definition:
Definition 6.3.1 (Structural Constraint Delta, C∆ ). Given an arbitrary class C, containing components, equations, and connections, the type of C has a defined integer attribute called structural constraint delta, C∆ . This attribute states, for C and all its subcomponents, the integer difference between the total number of defined equations and
variables.
The term structural indicates that the equations and variables are counted as they are
declared in the model. For example, two linearly dependent equations in an equation
system will still be counted as two separate equations. Hence, C∆ = 0 for a system of
equations does not guarantee a unique solution, it will only indicate that a single solution
might exist. If C∆ < 0, we have an under-constrained problem with more unknowns
6.3 The Approach of Structural Constraint Delta
81
than equations, which might give an infinite number of solutions. If C∆ > 0, we have an
over-constrained system of equations, which most likely will not give a unique solution.
However, because the algorithm for computing C∆ does not check if equations are linearly independent or not, a system with C∆ > 0 may be solvable. To be able to guarantee
that a system of equations has a unique solution, complete knowledge of the entire system of equation must be available. Because this is obviously not possible when inspecting
components separately, the value of C∆ only provides a good indication whether a system
of equations has a unique solution or not.
For example, if C∆ is to be calculated for the types of the models given in Figure 6.3,
the difference between the number of equations and variables in the model gives the value
of C∆ . In this case, C∆ = 0 for A and C, but C∆ = −1 for B. Because our models so
far only contain variables and equations, calculating C∆ is straightforward. However, if a
model contains hundreds of subcomponents, using connections, connectors, and records,
the resulting flattened system might consist of thousands of equations. To be able to
formulate algorithms for calculating C∆ , we need another definition:
Definition 6.3.2 (Constraint Delta Effect, E∆ ). Let C be an arbitrary class containing
two elements c1 and c2 that are instances of classes C1 and C2, which contain only
elements and no equations or connections. Given an equation or connection E located
in C representing a relation between c1 and c2, the constraint delta effect E∆ is a type
attribute of both C1 and C2, which states the effect E has when computing C∆ of C.
Note that C∆ is not the same as E∆ . Simply stated, we say that E∆ of two elements
represents the change of the current model’s C∆ when an equation or connection is introduced between the two elements. For example, if we in model B in Figure 6.3 introduce
a new equation q = 2 * p, this equation will have the effect of changing model B’s
C∆ from −1 to 0. Therefore, involved variables q and p, are said to have E∆ = 1 (or
to be precise; the attributes to the types of the elements). However, we will soon see that
elements do not always have E∆ = 1.
6.3.1 Algorithms for Computing C∆ and E∆
In this section, we present algorithms for calculating C∆ and E∆ . Even if the algorithms
for calculating the type attributes C∆ and E∆ could be stated by using a formal type
system, we have chosen to illustrate the algorithm more informally using pseudo-code
algorithms. The main reasons for this are that the Modelica language itself has currently
no formal semantics or type system and the target audience of this chapter is not only
computer scientists, but also engineers from the modeling and simulation community.
It is important to stress that C∆ and E∆ are defined as attributes to the types of
the classes, and not for the classes themselves. This implies that when calculating the
value for a specific class C, we do not need to recursively calculate C∆ and E∆ for each
subelement because they are already defined by the type of the elements4 . The process
of calculating C∆ and E∆ is a form of type inference, i.e., the type attributes are inferred
from equations given in the class and types of the elements in the class.
4 In FM, we have made the assumption that variables are always bound to a value without circular dependencies. Unfortunately cannot this be guaranteed in full Modelica.
82
6 Over- and Under-Constrained Systems of Equations
Algorithm 1: Compute C∆ of a class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Input: An arbitrary Class
Output: C∆ of the class
C∆ ← 0
switch Class do
case model
foreach e ∈ getElements(Class) do
C∆ ← C∆ + getDelta(e)
if hasDefaultValue(e) then
C∆ ← C∆ + 1
foreach m ∈ getModifiedElements(e) do
if not hasDefaultValue(m) then
C∆ ← C∆ + 1
foreach e ∈ getEquations(Class) do
C∆ ← C∆ + getEffect(e)
foreach c ∈ getConnectors(Class) do
Poutside ← FALSE
Pinherited ← FALSE
if not isVisited(c) then
traverseConnectorGraph(c)
if Poutside then
C∆ ← C∆ + getOutsideAdjustment(c)
foreach b ∈ getBaseClasses(Class) do
foreach m ∈ getModifiedElements(b) do
if not hasDefaultValue(m) then
C∆ ← C∆ + 1
C∆ ← C∆ +getDelta(b)
case record
foreach e ∈ getElements(Class) do
C∆ ← C∆ + getDelta(e)
foreach b ∈ getBaseClasses(Class) do
C∆ ← C∆ + getDelta(b)
case connector
foreach e ∈ getElements(Class) do
if not hasFlowPrefix(e) then
C∆ ← C∆ + getDelta(e)
foreach b ∈ getBaseClasses(Class) do
C∆ ← C∆ + getDelta(b)
case variable
C∆ ← −1
end
The algorithm for computing C∆ is given in Algorithm 1. This algorithm uses a help
function defined in Algorithm 2. The algorithm for computing E∆ is listed in Algorithm 3. Note that the indentation of the algorithms is significant and delimits blocks for
the foreach, if, and switch statements.
6.3 The Approach of Structural Constraint Delta
83
Algorithm 2: traverseConnectorGraph(c1)
1
2
3
4
5
6
7
8
9
10
Input: Connector c1 from which graph traversal starts
Output: Global variables Poutside , Pinherited , and C∆
if ((isOutside(c1 ) and isInherited(c1 )) or ((isOutside(c1 )
or isInherited(c1 )) and (Poutside or Pinherited )) then typeCheckingFailed()
else
markAsVisited(c1 )
Poutside ← Poutside or isOutside(c1 )
Pinherited ← Pinherited or isInherited(c1 )
foreach c2 ∈ getAdjacencyConnectors(c1 ) do
if not isVisited(c2 ) then
C∆ ← C∆ + getEffect(getTypeOf(c2 ))
traverseConnectorGraph(c2 )
Algorithm 3: Compute E∆ of a class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Input: An arbitrary Class
Output: E∆ of the class
E∆ ← 0
switch Class do
case record
foreach e ∈ getElements(Class) do
E∆ ← E∆ + getEffect(e)
foreach b ∈ getBaseClasses(Class) do
E∆ ← E∆ + getEffect(b)
case connector
foreach e ∈ getElements(Class) do
if hasFlowPrefix(e) then
E∆ ← E∆ −getEffect(e)
else E∆ ← E∆ + getEffect(e)
foreach b ∈ getBaseClasses(Class) do
E∆ ← E∆ + getEffect(b)
case variable
E∆ ← 1
end
To make the algorithms more easy to follow, the following help functions are defined:
• getAdjacencyConnectors (c) - the set of connectors that are directly connected to c by
connect-equations declared in the local class.
• getBaseClasses (C) - the set of types for the base classes to C.
• getConnectors(C) - the set of accessible connectors that are used by connections in class C.
All connectors are initially marked as unvisited.
• getDelta(t) - attribute C∆ part of type t.
• getElements(C) - the set of types for elements part of class C.
• getEquations(C) - the set of equations part of the local class C, excluding connect-equations
84
6 Over- and Under-Constrained Systems of Equations
and equations from base classes. Each element in the set represents the type of the expressions declared equal by the equation.
• getEffect(t) - the attribute E∆ part of type t.
• getModifiedElements(e) - the set of elements’ types in e, which is modified by modification
equations.
• getOutsideAdjustment(c) - an integer value representing adjustments to be made if connector c is part of a connector set that is connected to an outside connector. The integer value is
equal to the positive number of flow variables inside connector c.
• getTypeOf(c) - the type of connector c.
• hasDefaultValue(e) - TRUE if element type e has a defined default value.
• hasFlowPrefix(e) - TRUE if element e is prefixed with keyword flow.
• isInherited(c) - TRUE if connector c is inherited from a base class.
• isVisited(c) - TRUE if connector c is marked as visited.
• isOutside(c) - TRUE if connector c is seen as an outside connector in the local class.
• markAsVisited(c) - mark connector c as visited.
• typeCheckingFailed() - terminates the type because two outside or inherited connectors are
connected, or a connected connector is both outside and inherited.
Computing C∆ - Equations, Inheritance, and Modification
We start by illustrating the algorithms using trivial examples, where the models only
contain equations, records, and variables. Consider the following FM listing:
record R
Real p;
Real q;
end R;
C∆ =-2 E∆ =2
C∆ =-1 E∆ =1
C∆ =-1 E∆ =1
model A
R r1;
R r2;
Real p;
equation
r1 = r2;
end A;
C∆ =-3
C∆ =-2 E∆ =2
C∆ =-2 E∆ =2
C∆ =-1 E∆ =1
model B
Real y=10;
end B;
C∆ =0
C∆ =0 E∆ =1
model M
extends A(p=1);
B b1(y=20);
B b2;
equation
b1.y = p;
end M;
C∆ =-1
C∆ =-2
C∆ =0
C∆ =0
6.3 The Approach of Structural Constraint Delta
85
Model M extends from model A, which implies that all equations and elements in A will
be merged into M. Model A contains two instances of record R. If each of these models
were to be compiled separately, we would need to calculate C∆ for each of the models
without any knowledge of the internal semantics of the subcomponents, i.e., the equations.
Calculated C∆ and E∆ for every class and element are given to the right in the listing.
Consider Algorithm 1, which takes an arbitrary class as input and calculates the C∆
value for this class. First, we can see that calculating C∆ of a record simply adds the
C∆ value for each element (rows 26-27), which in the case of record R gives C∆ = −2
because R holds 2 variables. In Algorithm 3, we can see that calculating the effect of R
gives E∆ = 2. But what does this mean? Recall that E∆ , given in Definition 6.3.2, states
the effect on C∆ when connecting two elements. In model A, an equation r1 = r2 is
given, which uses record R. This equation will after elaboration generate two equations,
namely r1.p = r2.p and r1.q = r2.q, which is why E∆ for R is 2. The rest of the
procedure for computing C∆ of model A should be pretty straightforward by following
Algorithm 1. Note that only C∆ and not E∆ is given for models because models are not
allowed to be interconnected.
The more interesting aspects of calculating C∆ in this example are shown in model M.
First of all, we can see that model M extends from A, which results in that C∆ of A is added
to C∆ of M (see rows 20-24 in Algorithm 1). Because variable p is modified with p=1, we
see that C∆ is increased by E∆ of the type of p, i.e., Real. Hence, the C∆ contribution
from base class A is −2. The C∆ value for model B is 0. When instantiated to element
b1 in model M, its element y is modified with y=20. However, this modification does not
model K
C ic1;
C ic2;
end K;
connector C
flow Real x;
Real y;
end C;
model M
K a;
K b;
C oc1;
C oc2;
equation
connect(a.ic1, oc1);
connect(a.ic2, b.ic1);
connect(b.ic2, oc2);
end M;
Figure 6.4: Model M with inside connectors (e.g. a.ic1 and b.ic2) and outside
connectors (oc1 and oc2).
86
6 Over- and Under-Constrained Systems of Equations
effect C∆ because y already has a default value (see rows 8-10 in Algorithm 1). Finally,
we can see that the total calculation of M will result in a C∆ value of −1.
Computing C∆ - Connectors, Connections, and Flow Variables
Consider the source code listing and graphical representation given in Figure 6.4. Model
M contains components a and b, which are instances of model K. Each model consist of
several connector instance all instances of a connector class C.
The semantics of the Modelica language distinguish between outside connectors and
inside connectors , where the former are connector instances denoting the border of a
model, e.g., oc1 and oc2, and the latter represent connectors available in local components, e.g., a.ic1, a.ic2, b.ic1, and b.ic2. Note that a connector instance can be
seen as both an outside and an inside connector, depending which model is being processed. In this example we are looking at model M.
Calculating C∆ of connector C can be achieved by using rows 30-35 in Algorithm 1.
On row 32, we can see that C∆ is only added if the variable has not got a flow prefix. The
reason for this is that an unconnected flow variable has always a defined default equation,
setting its value to 0. Hence, introducing a flow variable gives one extra variable and one
equation, i.e., C∆ = 0. Further inspection of the algorithm yields C∆ = −2 for model K.
Calculating C∆ of M is more complicated. On row 13 in Algorithm 1 it is stated that
we iterate over all involved connectors, in this case a.ic1, a.ic2, b.ic1, b.ic2,
oc1, and oc2. Variable Poutside becomes TRUE if the algorithm has passed an outside
connector, and Pinherited becomes TRUE if it has passed an inherited element. The latter
case will not be illustrated in this example. The first thing to notice is that the connector
graph is traversed by using the recursive function traverseConnectorGraph(), listed in
Algorithm 2. The algorithm performs a depth-first search visiting each connector (vertex)
only once, by marking it as visited. Note that function traverseConnectorGraph() has side
effects and updates the variables Poutside , Pinherited , and C∆ . Each connect-equation
(edge) in the graph contributes to the C∆ of the class being computed, by adding E∆ of a
connector in the connection (see row 9 in Algorithm 2). Because all connectors traversed
in one iteration of the foreach loop are connected (row 13-19 in Algorithm 1), all types of
the connectors hold the same value of E∆ .
By using Algorithm 3, rows 9-12, we can see that E∆ = 0 for connector C. Consequently, all the connections in model M will not change the value of C∆ . Why is this
the case? We know that connecting non-flow variables will always result in an extra
equation, i.e., for non-flow variables, E∆ must be 1. However, when connecting two
flow variables, one equation is added, but two default equations are removed. For example in connect(a.ic2, b.ic1), the two default equations a.ic2.x=0 and
b.ic1.x=0 are removed and replaced with the sum-to-zero equation:
a.ic2.x + b.ic1.x = 0
Hence, the effect of connecting two flow variables is E∆ = −1.
There are several aspects covered by the algorithms that we have not covered in detail.
The following items briefly describe some of these issues:
• If cycles appear in the connector graph, there exists a redundant connect-equation
6.4 Prototype Implementation
87
which does not contribute to the value of C∆ . For example, if connections
connect(oc1,b.ic1) and connect(a.ic1,a.ic2) would be introduced
in M, one connection would be redundant. This issue is handled by making sure that
connectors are only visited once (see rows 7-10 in Algorithm 2.)
• Connecting an inside connector to an outside connector does not give the same
effect on C∆ as connecting inside to inside. For example, when connecting oc1
to a local connector inside M, the default variable oc1.x=0 will not be removed.
This default equation will only be removed when oc1 is connected outside model
M, i.e., when another model is using M as a component. This issue is managed on
rows 18-19 in Algorithm 1.
• The algorithm does not allow direct or indirect connections between outside connectors. For example, a connection connect(oc1,b.ic2) would generate a
type checking error (see row 1-2 in Algorithm 2). The same semantics hold for connections between connectors inherited from base classes. We use this conservative
approach because without it, the type of a class must be extended with information
regarding the connectors that are connected.
6.3.2 Extending the Type System with C∆
The previous sections describe how we can calculate C∆ and E∆ of classes, resulting in
value attributes for types in the language. However, this is of no use if we do not apply this
new information to the type system. A new extended version of the Featherweight Modelica language, denoted FM∆ , is defined by extending Definition 6.2.1 and Definition 6.2.2
for type-equivalence and subtyping with the following definitions:
Definition 6.3.3 (Type-equivalence and C∆ ). For any types T and U to be type-equivalent,
Definition 6.2.1 must hold and the C∆ -value of T and U must be equal.
Definition 6.3.4 (Subtyping and C∆ ). For any types S and C, S is a supertype of C and
C is a subtype of S if Definition 6.2.2 holds and the C∆ -value of S is equal to that of C.
Hence, the extended language FM∆ guarantees that the difference between declared variables and equations does not change when using the rule of subsumption. If we recall the
models listed in Figure 6.3, we can now see that model C is a subtype of model A, but
model B is not.
6.4 Prototype Implementation
To validate and verify our algorithms, a prototype Featherweight Modelica Compiler
(fmc) was implemented consisting of a type-checker for FM∆ , where C∆ and E∆ are
automatically inferred and represented as attributes to the types. The prototype compiler
was implemented as a batch-program, which takes an FM∆ .mo-file (containing FM∆
models) as input and returning to standard output the pretty-printed type of the last model
defined in the .mo-file.
To validate the correctness of our solution, the following procedure has been used:
88
6 Over- and Under-Constrained Systems of Equations
1. Create relevant models in FM∆ .
2. Run the prototype compiler for FM∆ on the models. The output is the listed type
of the model including C∆ information.
3. Elaborate the model and manually inspect the flat Modelica code generated by the
compilers Dymola version 6 [45] and OpenModelica version 1.4.1 [52].
The above approach gives us confidence that the algorithm is correct with respect to the
Modelica semantics, but it does not give any guarantees. The best option would of course
have been to be able to prove the correctness of the algorithm. However, we face two
problems with this. Firstly, the algorithm itself is fairly complicated, which is the effect of
complications of the Modelica connect semantics using connection graphs. The question
arises naturally if the connection semantics needs to be that complicated. In Section 11.2
we will propose an alternative semantics for describing connections compared to Modelica, which we argue has a simpler semantics. Secondly, to be able to prove correctness
compared to Modelicas elaboration semantics, we need a formalization of that elaboration semantics. Because this is not available, we have instead justified the correctness by
implementation and testing.
We will now analyze, by using a simple circuit example, how the concept of structural constraint delta attacks the problems of constraint checking with separately compiled model components, and error detection and debugging. In the examples, fmc and
Dymola version 6 are used when testing the models.
6.4.1 Constraint Checking of Separately Compiled Components
Consider the following listing, stating the model Resistor, a connector Pin and a base
class TwoPin:
model TwoPin
Pin p;
Pin n;
Real v;
Real i;
equation
v = p.v - n.v;
0 = p.i + n.i;
i = p.i;
end TwoPin;
connector Pin
Real v;
flow Real i;
end Pin;
model Resistor
extends TwoPin;
Real R = 100;
equation
R*i = v;
end Resistor;
When using fmc, each of these models is separately type checked. For example, when
typechecking model Resistor, model TwoPin and connector Pin are not elaborated.
Instead, only the types of TwoPin and Pin are used. This information is available after
these classes are compiled.
Below the output generated by fmc is listed, with some pretty printing added for
readability:
model classtype C∆ =0
public final connector objtype C∆ =-1 E∆ =0
89
6.4 Prototype Implementation
nonflow Real objtype
flow Real objtype i;
end p;
public final connector
nonflow Real objtype
flow Real objtype i;
end n;
public modifiable Real
public modifiable Real
public modifiable Real
end
v;
objtype C∆ =-1 E∆ =0
v;
objtype v;
objtype i;
objtype* R;
The lines above represent the type of model Resistor. Note the difference made between class type (the type of a class that can be instantiated), and a objtype (the type
of an object that has been instantiated by a class). The type’s of elements p and n have
C∆ = −1 and E∆ = 0. The latter indicates that when the Resistor model is used
by connecting p or n, C∆ will not change. Finally, we can see that that C∆ = 0 for the
whole type of Resistor.
Now, if the following code is added to our .mo-file, we have a complete model named
Circuit that we can simulate.
model Ground
Pin p;
equation
p.v = 0;
end Ground;
model VsourceAC
extends TwoPin;
Real VA = 220;
Real f = 50;
Real PI = 3.1416;
equation
v = VA*sin(2*PI*f*time);
end VsourceAC;
model Inductor
Pin p;
Pin n;
Real v;
Real i;
Real L = 1;
equation
L*der(i) = v;
end Inductor;
model Circuit
protected
replaceable Resistor R1(R=10);
replaceable Inductor L(L=0.1);
VsourceAC AC;
Ground G;
equation
connect(AC.p, R1.p);
connect(R1.n, L.p);
connect(L.n, AC.n);
connect(AC.n, G.p);
end Circuit;
Trying to simulate the above model Circuit in the commercial Modelica environment
Dymola, the error feedback states that it is not possible to simulate it because there are 22
equations and 25 variables in the flattened equation system.
Executing the model in fmc, we get the response that model circuit has C∆ = −3,
which corresponds to the message Dymola reported. Note that Dymola had to elaborate
all the models to a flattened system of equation to get to this result. fmc on the other
hand could use the separately type checked components and just use the types of these
90
6 Over- and Under-Constrained Systems of Equations
components to get the same result. Hence, this example illustrates how our approach can
be used to enable separate compilation of components.
6.4.2 Error Detection and Debugging
Now the following question arise: How can we know where the problem is located? The
user needs to either analyze the model code or to inspect the flat system of equations. In
both cases, this problem seems hard to manage.
If we run this model in fmc, we get the following type information for model Circuit
(for readability, parts of the type are replaced by a dotted line):
model classtype C∆ =-3
protected replaceable model objtype C∆ =0
...
end R1;
protected replaceable model objtype C∆ =-3
...
end L;
protected modifiable model objtype C∆ =0
...
end AC;
protected modifiable model objtype C∆ =0
...
end G;
end
Analyzing the type information, it indicates that it is component L, which is an instance of Inductor that probably causes the under-constrained system. After a closer
look, we notice that Inductor is not extending from TwoPin, as it should. After replacing the old Inductor model with
model Inductor
extends TwoPin;
Real L = 1;
equation
L*der(i) = v;
end Inductor;
it is possible to simulate the model.
Now, let us assume that we want to build a larger model having model Circuit as
a subcomponent. However, this time we do not want to use a Resistor in Circuit.
Instead, the goal is to redeclare R with a temperature dependent resistor called
TempResistor. Consider the following models:
model TempResistor
extends TwoPin;
Real R;
//
Real RT=0;
//
Real Tref=20; //
Real Temp;
//
equation
Resistance at. reference temp.
Temp. dependent resistance
Reference temperature
Actual temperature
6.5 Chapter Summary and Conclusions
91
v = i * (R + RT * (Temp-Tref));
end TempResistor;
model Circuit2
extends Circuit(redeclare TempResistor R1(R=35));
end Circuit2;
Trying to simulate this model in Dymola results in a flattened model with 28 variables and
27 equations, which cannot be simulated. By elaborating all components and analyzing
the system of equations, Dymola hints that R1 is structurally singular.
However, using fmc, this model does not even pass the type checker. The compiler
reports that C∆ for the original type is 0 (Resistor), but the redeclaring model’s type
is -1 (TempResistor). Hence, the subtyping rule is not legal and the redeclaration
is incorrect. The following listing shows a correct redeclaration, where the temperature
parameter Temp has been assigned a value.
model Circuit3
extends Circuit
(redeclare TempResistor R1(R=35, Temp=20));
end Circuit3;
Consequently, our approach finds the incorrect model at an early stage during type checking. Furthermore, because the type checking was performed on precompiled models,
there is no need for elaborating the model’s subcomponents. Hence, this approach is not
only useful for separate compilation, but also for users when locating errors in models.
6.5 Chapter Summary and Conclusions
We have presented the concept of structural constraint delta (C∆ ) for equation-based
object-oriented modeling languages. Algorithms for computing C∆ were given, and it
was shown how C∆ is used to determine if a model is under- or over-constrained without
having to elaborate a model’s components.
We have also illustrated how the concept of C∆ allows the user to detect and pinpoint
some model errors. The concept has been implemented for a subset of the Modelica
language and successfully tested on several models.
92
6 Over- and Under-Constrained Systems of Equations
Part II
The Modeling Kernel Language
93
7
Introduction to Functional
Programming in MKL
our study of the Modelica language in Part I, we have seen that the language is
large and complex, providing many possibilities for advanced modeling. However,
we have also concluded that it is hard to formalize because it is large and complex.
In this second part of the thesis, we present a new language called the Modeling Kernel
Language (MKL). Instead of taking a top-down approach of trying to formalize a large
language such as Modelica, this research is following a bottom-up approach, where we
formally define a small language. The objective and hope is then that the small kernel
language can be extended with both new modeling constructs, as well as functions for
manipulating and making use of the mathematical models. The approach that we are
exploring is that these extensions are not added to the core of the language itself, but are
instead added as library functions written in MKL. This approach concerns the research
questions stated in Section 1.4.3 regarding the problem of designing an expressive and
extensible EOO language that is formally defined.
The MKL language is fundamentally a statically typed functional language. The rationale for designing a functional language is because we would like to base it on a well
known and proven theory, in this case the lambda calculus [12].
In this introductionary chapter to Part II, we first explain the fundamentals of functional programming by introducing the syntax and the standard functional parts of MKL,
i.e., language constructs that can be found in languages such as Haskell [134] or Standard
ML [98] (Section 7.1). This is followed by a brief introduction to the lambda calculus
(Section 7.2).
Part II consists of the following chapters:
F
ROM
• Chapter 8 - Modeling in MKL. In this chapter we first give a brief description
of basic modeling in MKL. This is followed by introducing the concept of higherorder acausal modeling (HOAM). By providing a simple model in the electrical and
mechanical domains, we show the expressive power of the concept. This chapter
also informally introduces the modeling capabilities of the MKL.
95
96
7 Introduction to Functional Programming in MKL
• Chapter 9 - Intensional Analysis of Models. In this chapter, we demonstrate how
MKL can also be used for intensional analysis of the models, i.e., to inspect and
analyze the equation system of the model and to synthesize output for different
purposes.
• Chapter 10 - Semantics of MKL. In this chapter, we formally define the syntax and semantics of the core of MKL, which is an extension of the simply typed
lambda calculus. The semantics forms the foundation of both the modeling capabilities and the ability of intensional analysis of models. Both a small-step dynamic
semantics and a static type system are formally defined. We also prove type safety
for the core language.
• Chapter 11 - Elaboration Semantics. We describe and give a formal definition of
the elaboration semantics used for elaborating models down to equation systems.
The problem of extracting information from models is discussed and a solution is
proposed.
• Chapter 12 - Implementation, Verification, and Evaluation. In this final chapter
we first give an overview of the prototype implementation of MKL. This is followed by two examples of the use of models - one for direct simulation and one for
exporting to Modelica code. We explain how we verify the solution and we discuss
and evaluate our approach with regards to safety, expressiveness, extensibility, and
performance aspects.
7.1
Functional Programming in MKL
There are many different opinions of what functional programming actually means. To
give an intuition, we quote Hutton [69, p. 2]:
“functional programming can be viewed as a style of programming in which
the basic method of computation is the application of functions to arguments.
In turn, a functional programming language is one that supports and encourages the functional style”
The modeling kernel language (MKL) is a functional programming language, specially
designed for providing EOO language functionality within libraries. The current version
that we present in this thesis should be seen as a research language for exploring this
approach.
MKL has a syntax style where expressions are similar to OCaml [74], and types have
similarities to Haskell [134], and, to some extent, Clean [125]. The subset that is presented in this chapter only consists of standard constructs, available in most functional
programming languages. The extensions are presented in the following chapters.
The functional programming style encourages declarative programming, where function applications do not have side effects , i.e., a function applied to the same argument
should always return the same value regardless of its context. Languages where function applications do not have side effects are often called pure functional languages (e.g.,
97
7.1 Functional Programming in MKL
Haskell or Clean).1 In other functional languages (e.g., OCaml or Standard ML [98])
pure functional programming is encouraged, but the language also supports effectful constructs, i.e., constructs with side effects, e.g., reference updates and destructive arrays.
MKL is within the latter category, where handling of unknowns (explained in coming
chapters) and destructive arrays are effectful constructs that are part of the language.
A functional languages have a defined evaluation strategy. The language can be strict
(eager) meaning that arguments to functions are evaluated before they are passed to the
function at function call. Examples of functional programming languages within this category are OCaml, Standard ML, and Common LISP [137]. A FP language can also use an
evaluation strategy when arguments are supplied to a function without first evaluating the
arguments. In its simplest form, this is called call-by-name , but to avoid recomputation of
expressions a more efficient approach is often referred to as call-by-need . This approach
is used by languages such as Haskell and Clean. MKL is within the former class, i.e. a
strict functional language.
A program in MKL is an expression. For example 4 + 5 * 3 is an expression for
adding and multiplying integers. When executing a program, the expression is evaluated
to a value. We write e −→∗ v meaning that e is evaluated to the value v in zero or more
steps, and e −→ e′ meaning that e is reduced to e′ in one step. For example 4 + 5 * 3
−→∗ 19 and 4 + 5 * 3 −→ 4 + 15.
Each expression e has a (or belongs to a) type T , written e : T . That is, the type
predicts the kind of value that the expression reduces to. For example 4 + 5 * 3 : Int,
and 19 : Int have both type Int because the type of an expression is preserved during
evaluation. MKL is statically typed 2 , meaning that all expressions in a program can be
given a type statically, before evaluation.
In MKL, there are four basic types: Int, Real, Bool, and String. Overloading is not allowed and therefore different operators are used for different types. Similar to OCaml, operators for real types are given a dot suffix. For example, expression 12.10 *. 10. -. 50. is evaluated to 52.10. Boolean literals are true and
false, with infix logical operators && for and, || for or, and ! for negation. Two strings
can be concatenated using infix operator ++, e.g., "My " ++ "string\n" is evaluated to "My string\n". Escape sequences, such as new line \n can be given inside
a string. For a full list of available functions and operators that are built-in to MKL, see
Appendix D.1.
7.1.1 Higher-Order Functions and Currying
In functional languages, the most fundamental language construct is a function. Functions
correspond to partial mathematical functions, i.e., a function f : A → B gives a mapping
from (a subset of) the domain A to the codomain B. Anonymous functions (also called
lambda abstractions) are functions without names. Such functions are also expressions.
An anonymous function can be expressed as
fun x:T -> e
1 Haskell is using monads and Clean uniqueness types for handling side effects, such as keyboard input, file
I/0 etc. without compromising function purity)
2 We will later in Part II also introduce a certain level of dynamic typing.
98
7 Introduction to Functional Programming in MKL
where x is the parameter name, T the parameter’s type, and e the body of the function.
MKL is an explicitly typed language, meaning that the types of parameters must be given
by the user explicitly in the program. A lambda abstraction has always just one parameter
and its type is written using arrow syntax T1 -> T2 , where the left hand side of the arrow
is the type of the parameter, and the right hand side the type of the return value. For
example, the anonymous function fun a:Int -> a + 1, where the arrow points to the
function body, has a parameter a of type Int, and a body a + 1. Because the type of
the body is also Int, the type of the whole function expression is Int -> Int.
In a function that takes more than one parameter, these parameters are not written as
in Java or C/C++ as a comma separated list enclosed in parenthesis. Instead, multiple
parameters are defined using currying, meaning that several parameters are defined by
composing several lambda abstractions. For example, consider
fun a:Int -> fun b:Int -> a * b
which is equivalent to
fun a:Int -> (fun b:Int -> a * b)
This function expression, of type Int->Int->Int, which takes two arguments as input and multiplies their values, can be partially applied , meaning that if only the first
argument is supplied, a new function with the remaining parameter is returned, e.g., the
expression
(fun a:Int -> fun b:Int -> a * b) 5
−→ fun b:Int -> 5 * b
is reduced to a new function with type Int -> Int. Note that the expression in the
function body cannot be reduced any more because no argument has been supplied to the
function parameter b. Lambdas (anonymous functions denoted λ in the original calculus
instead of fun), currying, and partial applications are some of the key concepts that make
functional programming expressive and useful.
However, it is often convenient to give names to values. A MKL source code file
consists of a sequence of top-level definitions giving names to expressions. If the same
name is defined more than once, the last binding is used. For example, in
let
let
let
let
p
q
p
r
=
=
=
=
3
4
5
p + q
variable r will be bound to the value 9.
Because functions are values, they can be given names in the same way, i.e., by binding an anonymous function to a name using the let-construct:
let multiply = fun a:Int -> fun b:Int -> a * b
Alternatively, the function parameters can be moved to the left of the equal sign, thus
defining a function directly.
let multiply x:Int -> y:Int -> Int =
x * y
7.1 Functional Programming in MKL
99
Note that this notation is non-standard and can be seen as a mixture of Haskell’s convention of giving the arrow syntax above a function definition and OCaml’s syntax of
defining functions using let-binding. We are using the arrow notation both to name the
parameters, and to relate types to the parameter names. We have found this syntax fairly
intuitive and assume that its meaning is clear.
The type of multiply is Int -> Int -> Int, which is explicitly stated in the
last let-binding. The arrow notation is right associative, i.e., Int -> (Int -> Int)
is the same type, but (Int -> Int) -> Int is not. The latter is the type of a function that takes a function as argument and then returns an integer.
A careful reader might have noticed that the return type (the last type definition after
the last arrow) of the multiply definition is not necessary for the type checker because it
can be derived from the expression x * y because * is an integer multiplication operator
that always return results of type Int. This is true as long as the function is non-recursive.
For example, in the following definition of the factorial function
let fact n:Int -> Int =
if n == 0 then 1 else n * (fact (n-1))
the type checker needs the return type to be able to type check the function3 because the
function is recursive (fact refers to itself in the false branch of the if-expression).
Note that the syntax for function application does not use parentheses. Instead the
function to be applied is separated from its supplied arguments by one or more spaces.
A function call that in standard mathematical calculus or in languages such as C or Java
would appear as multiply(3,4) here appears as multiply 3 4. Parentheses are only used
for grouping and disambiguation. This is a function call syntax used by most functional
languages.
Function application has higher precedence than infix operators. For example, in the
expression
fact (multiply (1+2) 3)
the expression (1+2) is the first argument supplied to multiply and 3 the second
argument. The expression
fact ((multiply (1+2)) 3)
is equivalent because applications are left associative, but
fact (multiply 1+2 3)
would give a parse error.
In many situations, it is useful to pass a function as an argument to another function,
or to return a function as a result of executing a function. When functions are treated as
values and can be passed around freely as any other value, they are said to be first-class
citizens. In such a case, the language supports higher-order functions.
Definition 7.1.1 (Higher-Order Function).
A higher-order function is a function that
1. takes another function as argument, or
3 If
the types were inferred using, e.g., Hindley-Milner type inference, this would of course not be necessary.
100
7 Introduction to Functional Programming in MKL
2. returns a function as its result.
Let us first show the former case where functions are passed as values. Consider the
following function definition of twice, which applies the function f two times to y, and
then returns the result.
let twice f:(Real -> Real) -> y:Real -> Real =
f (f y)
The function twice can then be used with a function f that has type Real -> Real.
We can now define a function power2
let power2 x:Real -> Real = x *. x
and apply function twice to power2 (first argument) and a value 3. (second argument):
twice power2 3.
−→ power2 (power2 3.)
−→ power2 (3.*3.)
−→ power2 9.
−→ 9. *. 9.
−→ 81.
Because twice can take any function as an argument, we can apply twice to an anonymous function, passed directly as an argument to the function twice.
twice (fun x:Real -> 2. *.
−→ (fun x:Real -> 2. *. x
−→ (fun x:Real -> 2. *. x
−→ (fun x:Real -> 2. *. x
−→ 2. *. 7. -. 3.
−→ 11.
x -. 3.) 5.
-. 3.)((fun x:Real -> 2. *. x -.3.)5.)
-. 3.)(2. *. 5. -. 3.)
-. 3.) 7.
Let us now consider the second part of Definition 7.1.1, i.e., a function that returns another
function as its result. In mathematics, functional composition is normally expressed using
the infix operator ◦. Two functions f : X → Y and g : Y → Z can be composed to
g ◦ f : X → Z, by using the definition (g ◦ f )(x) = g(f (x)).
The very same definition can be expressed in a language supporting higher-order functions:
let compose g:(Real->Real) -> f:(Real->Real) -> (Real->Real) =
fun x:Real -> g (f x)
This example illustrates the creation of a new anonymous function and returning it from
the compose function. The function composes the two functions given as parameters
to compose. Hence, this example illustrates both that higher-order functions can be
applied to functions passed as arguments (using formal parameters f and g), and that new
functions can be created and returned as results (the anonymous function).
To illustrate an evaluation trace of the composition function, we first define another
function add7
let add7 x:Real = 7. +. x
7.1 Functional Programming in MKL
101
and then compose power2 and add7 together, forming a new function foo:
let foo = compose power2 add7
−→ let foo = (fun x:Real -> power2 (add7 x))
Note how the function compose applied to power2 and add7 evaluates to an anonymous function. Now, the new function foo can be applied to some argument, e.g.,
foo
−→
−→
−→
−→
−→
−→
4.
(fun x:real -> power2 (add7 x)) 4.
power2 (add7 4.)
power2 (7. +. 4.)
power2 11.
11. *. 11.
121.
7.1.2 Tuples, Lists, and Pattern Matching
Tuples are the simplest form of a compound type (also called product type), containing a fixed number of ordered expressions, where each expression can have a different
type. Tuples can be viewed as a simple form of records without record field names. A
tuple expression is given as a comma separated list of expressions enclosed in parentheses. For example, the tuple (21,"str",false) has three elements and has type
(Int,String,Bool). Hence, we write the type of tuples in the form (T1 , . . . ,Tn )
where n is the number of elements in the tuple.
A unit type 4 is similar to void in languages such as C. Both the unit expression
and its type are written as an empty tuple, i.e., (). The unit type is used as the result
type when a function has side effects and does not return an actual value, e.g., expression
print "a string\n" prints out a string to the standard output. The type of the function
print is String -> (), i.e., it takes a string as input and returns the unit expression,
i.e., no value. Hence, it is the side effect of printing the string to standard output that is of
interest in the computation.
A list is a sequence of expressions, where each expression has the same type. We
write [T ] for the type of a list, whose elements have type T . A list expression is
written as a comma-separated list of expressions (the elements of the list), enclosed
within brackets. For example, [3,1,7,0,3] is list of integers with type [Int], and
["this","is","a","list"] is a list of strings with type [String]. The expression
["text",32.10] will be rejected by the type checker because the list contains elements
of both type String and Real. A list can contain other lists, for example, the expression
[[1,5,2],[3,2,5],[6,2,4]] is a 3 × 3 matrix represented as a nested list.
A list is built up of cons cells, i.e., element pairs where the first element is an element
of the list and the second element the rest of the list. A cons constructor is written using
the infix operator ::. For example 3::9::20::[] is a list of 3 elements. The last
expression [] is the empty list, which is always the last element of a cons sequence. The
cons operator is right associative, i.e., the expression 3::(9::(20::[])) denotes the
4 The name unit type is often used in literature for functional languages. Note that this has nothing to do with
physical units of measurement.
102
7 Introduction to Functional Programming in MKL
same expression. The syntactic form of a comma separated list is just syntactic sugar for
the cons cells, i.e., [3,9,20] is just another syntactic form of the same expression.
Pattern matching is a way for deconstructing tuples and lists, i.e., to take them apart.
A match-expression in its simplest syntactic form appears as follows
match e with | p1 -> e1 . . . | pn -> eb
where e is the expression to be matched, bar | preceding each matching case, ek the chosen
expression if the pattern pk is matched, where k ∈ {1 . . . n} for n matching cases. For
example,
let weekend day:Int -> String =
match day with
| 6 -> "Saturday"
| 7 -> "Sunday"
| x -> "Number " ++ (int2string x) ++ " is not a weekend day"
defines a function weekend that returns a string with the name of a weekend day. Each
matching case is tried in order, and if the pattern matches, the expression on the right
hand side of -> is evaluated and returned. If none of the literal values 6 or 7 matches, the
pattern variable x matches any value and is bound to the matching value in the matching
process. In this case, the built-in function int2string is used to generate a return
string.
Pattern matching can be used together with recursion and higher-order functions.
let filter p:(Int -> Bool) -> list:[Int] -> [Int] =
match list with
| x::xs -> if p x then x::(filter p xs) else filter p xs
| [] -> []
The function filter takes a predicate p, a list of integers list and returns a new list,
with all elements that satisfy the predicate. The first case of the match-expression takes
apart a list using the cons operator, where x is the first element of the list and xs matches
the rest of the list. If the list is not empty, this matching case is used and the guard of
the if-expression is evaluated, i.e., the predicate function p is applied to the element x.
If it returns true, then a new cons cell is created with element x and with a recursive
call filter with the rest of the list xs. If the guard of the if-expression is false, the
recursive call is performed without adding x to the list, i.e., the element is filtered out. If
the list is empty (matching the empty list []), the empty list is returned. Expression
filter (fun x:Int -> x < 10) [3,22,8,99,4,12]
−→∗ [3,8,4]
shows how an anonymous function is used as a predicate to filter integers smaller than 10.
Consider now the following example that illustrates several other properties of the
matching construct:
let foo t:([String],Int) -> String =
match t with
| (["magic"],x) when x > 77 -> "The magic combination"
| ([x,y],_) -> x ++ y
103
7.1 Functional Programming in MKL
First, it shows that patterns can be nested in an arbitrary way. In this case we have a list
["magic"]and a number represented by x as part of a tuple. In the first line, we match
a singleton list with a specific value "magic". The pattern variable x is bound and then
used in the when pattern guard, meaning that the case will only be selected if x is greater
than 77. The second case shows how a list with two pattern variables x and y is bound if
the list has exactly two elements. We also introduce the wildcard pattern _ which matches
any value. Some example expressions
foo (["magic"],100)
foo (["two ","strings"],10)
foo (["one"],12)
−→∗
−→∗
−→∗
"The magic combination"
"two strings"
error
The last example shows an example where none of the cases matches. In such a case, a
runtime error is generated.5
If certain types are used in several functions, it could be practical to give new names
to types. At the top-level, new type aliases can be given, e.g.,
type Vector = (Real,Real,Real)
defines a vector in the Cartesian coordinate system. Because tuples have a defined shape
at compile time (in contrast to lists which can be either cons or the empty list), the letconstruct can be used directly as syntactic sugar to deconstruct a tuple. The following
function defines the cross product (or vector product):
let crossProduct a:Vector -> b:Vector -> Vector =
let (a1,a2,a3) = a in
let (b1,b2,b3) = b in
(a2 *. b3 -. a3 *. b2,
a3 *. b1 -. a1 *. b3,
a1 *. b2 -. a2 *. b1)
Note that we are here using both let-expressions at the top-level, as well as local letexpressions inside a function. In the latter case, the in keyword is used to separate the
expressions, i.e., syntax let p = e1 in e2 states that expression e1 is matched against
pattern p. The free pattern variables in p are bound and then available in e2 . Finally, we
show how the crossProduct function can be applied to some example vectors:
crossProduct (2.,8.,33.) (15.,22.,9.)
−→∗ (-654.,477.,-76.)
3
7.1.3 Equality, Abstract Data Types, and Modules
In the current version of MKL, there is no support for parametric polymorphism . The
main rationale for excluding such useful language property is that further research is
needed to study the relation of polymorphism with the language extensions presented
in the next chapters.
5 In future versions, exhaustive checking of matching rules could be done at compile time. However, this is
not available in the current prototype.
104
7 Introduction to Functional Programming in MKL
However, to be able to evaluate the approach taken in the thesis, a fairly efficient implementation is needed. For that reason polymorphic built-in abstract data types (ADTs)
for handling finite sets, mapping between key value pairs, and efficient random access
arrays have been added to the language. Appendix B defines their interfaces and the rest
of this subsection gives a brief overview of their uses.
MKL has a built-in polymorphic infix operator == for structural equivalence test between two values. It is polymorphic in the sense that the expression on the left and right
hand sides can have any type, as long as the types are equal. Hence, an implementation
traverses data structures and/or functions to determine if they are equal or not. Functions
are syntactically compared for equality up to α-conversion, i.e., the identifier names for
function parameters do not matter. For example, the two expressions
321 == 150 + 171
(fun x:Int -> 1 + x,"text") == (fun y:Int -> 1 + y,"text")
both evaluate to true, but the expressions
[1,4,9,2] == [90,21,3]
(fun x:Bool -> true && false) == (fun x:Bool -> false)
both evaluate to false. Note that comparison of equality is always performed on values,
and therefore the right hand side of the first expression is first evaluated to the value 321.
The second expression evaluates to true due to α-conversion, i.e., that bound variables
can be renamed. The third is obviously false because both the size of the list and their
elements differ. Finally, the fourth expression evaluates to false because functions are
values and MKL is using weak reduction, i.e., evaluation is not performed under function
abstractions. Besides equality of expressions, the functions of the ADTs need a comparison function to determine the total order over all types. This comparison function is not
reachable as a user function, but is used internally by the ADTs. Equality and comparison
of expressions are further discussed in Section 10.5.4.
All operations available within the set ADT are reached by prefixing the operator with
Set followed by a dot. An empty set is created with expression Set.empty. Elements
can be added by using Set.add, where the first argument is the element and the second
the set that should be extended. The returned value is the new set. Consider the following
example
let
let
let
let
let
s1 = Set.add 10 (Set.add 20 (Set.empty))
m1 = Set.mem 10 s1
s2 = Set.remove 10 s1
m2 = Set.mem 10 s2
l = Set.toList s1
where s1 evaluates to {10, 20}, m1 evaluates to true, s2 to {20}, m2 to false and l to
[20,10], where we have used the notation {e1 , e2 , ...} to denote a set constructed from
elements e1 , e2 , etc. It should be noted that set operations are purely functional, i.e.,
no destructive updates occur. For example, the remove operations did not remove the
element from s1; it just returned a new set s2 where the element was removed. The type
of a set is written Set T , where T is the type of the element in the set.
The Map ADT is used for storing a finite mapping of key - value pairs. The implementation is purely functional, i.e., no destructive updates occur and update operations always
7.2 Lambda Calculus and Operational Semantics
105
return a new map. We use a double arrow to denote the type of a map T1 => T2 , where
T1 is the type of the keys and T2 the type of the values. The operations are similar to the
set, e.g. Map.empty creates a new empty map, Map.add k v m adds a key k with the
value v to the map m, and then returns the new updated map. If the key already exists, the
returned map holds the new binding with value v. The operator Map.find k m returns
the value associated with the key k in m, if found. If not, a runtime error is reported. To
avoid this to happen, Map.mem k m should first be called to check if the key k exists in
m.
The Array ADT implements random access of fixed sized arrays. We write { T }
for the type of an array. For example, {(Real,Real)} is the type of an array of tuples,
whose elements are of type Real. Arrays differs from the other ADTs in that all of
its operations are not purely functional. For example, Array.set a p e destructively
replaces the element at position p in the array a with the element e. If an access is out of
bounds, a runtime error is reported.
Finally, the current version of MKL has a very simple system for separating code into
different modules. The prototype implementation does not yet support separate compilation or information hiding, e.g., to create ADTs. The import mechanism from separately
defined modules is a simple include mechanism. At the top-level, for example the lines
include Base
include Electrical
will include the definitions in file base.mkl and electrical.mkl into the current
module. However, the include mechanism ensures both that equivalent definitions are not
included twice and reports an error if the include statements of the modules introduce
circular dependencies. The approach taken here is preliminary and is likely to be changed
in future revisions of the language.
7.2 Lambda Calculus and Operational Semantics
In the following section, we give a brief introduction to the lambda calculus, as well as
the foundation of operational semantics.
7.2.1 Untyped Lambda Calculus
The lambda calculus was invented by Alonso Church in the 1930s. Today it forms the
foundation of many programming languages in general, and for functional programming
languages in particular. Several books have been written about the subject, where Barendregt [12] gives a comprehensive description of the foundations, Hindley and Seldin [67]
a perhaps more accessible introduction, and Pierce [124] details how it can be extended
with types and other language constructs to form programming languages.
The syntax of the lambda calculus is given with the following Backus-Naur Form
(BNF) grammar:
e ::= x | λx.e | e1 e2
(7.1)
where e is a lambda expression, x a variable, λx.e a lambda abstraction, and e1 e2 an
application. The above grammar should be understood as defining the abstract syntax of
106
7 Introduction to Functional Programming in MKL
the calculus, i.e., that ambiguities of precedence and associativity have been handled by
the earlier parsing stage from concrete syntax. When discussing calculi in this thesis,
we mean the abstract syntax. However, in examples and proofs, we need to write out
expressions concretely. We use parentheses to remove ambiguities, but to avoid too many
parentheses, we use the following convention:
The body of a lambda abstraction is counted as far to the right as possible, only
ending with a closing parenthesis or end of expression. For example, the expression
λz. λx. λy. x y z is equivalent to λz. (λx. (λy. x y z)), but not to λz.(λx. λy. x y) z,
where the latter states that z is supplied as an argument to the lambda abstraction binding
the variable x. The second convention is that function application is left associative, i.e.,
x y z is equivalent to ((x y) z).
Grammar (7.1) is a convenient short way of stating the abstract syntax. A more formal
definition can be giving inductively:
Definition 7.2.1 (Lambda expressions). Let X be the countable set of variable names.
The set of lambda expressions E is the smallest set such that
• if x ∈ X then x ∈ E
• if x ∈ X and e ∈ E then λx.e ∈ E
• if e1 ∈ E and e2 ∈ E then e1 e2 ∈ E
In the coming calculi we use the simpler form defining the syntax using BNF.
A variable x in a lambda abstraction λx.e is said to be bound by the abstraction if it
occurs free in the abstraction’s body e. The set of free variables of a lambda expression e
can be defined as a recursive function F V (e):
Definition 7.2.2 (Free variable).
F V (x)
F V (λx. e)
F V (e1 e2 )
=
=
=
{x}
F V (e) − {x}
F V (e1 ) ∪ F V (e2 )
For example, in λx. x y the variable x is bound by the lambda abstraction and y is a free
variable of the expression. In the expression λx. λy. λx. z y x, variable z appears free
and x and y are bound. Variable x is bound by the innermost lambda. The outermost
lambda does not bind any variables because x is not free in its body.
We write [x 7→ e]e1 meaning that all free occurrences of the variable x in e1 are
replaced/substituted by the expression e1 . We define substitution as follows:
Definition 7.2.3 (Substitution).
[x 7→ e]x
[x 7→ e]y
[x 7→ e](λy. e1 )
[x 7→ e](e1 e2 )
=
=
=
=
e
y
λy. [x 7→ e]e1
([x 7→ e]e1 )([x 7→ e]e2 )
if y 6= x
if x 6= y and y ∈
/ F V (e)
The computation of a lambda expression is performed by reducing expressions, so called
redexes. The rewriting rule
(λx.e1 ) e −→ [x 7→ e]e1
7.2 Lambda Calculus and Operational Semantics
107
is called the β-reduction. There are different evaluation strategies for the λ-calculus.
They defines which order the redexes are reduced.
In normal order evaluation, the outermost and leftmost redex is is reduced first. E.g.,
(λx. λw. x)((λy. y)(λz. z)) −→
(λw.(λy. y)(λz. z)) −→
(λw.(λz. z))
Note that evaluation occurs under lambda, i.e., evaluation proceeds in the body of the
lambda abstraction.
If we reconsider Definition 7.2.3, we see that the guards for the equations make the
substitution a partial function. We say that Definition 7.2.3 is capture avoiding, meaning
that a free variable cannot be accidentally captured by another lambda abstraction. For
example the expression λz. (λx. λz. x) z is reduced to λz. ([x 7→ z](λz. x)). However,
the partial definition of substitution does not apply because the binding variable z is free
in the substituting expression, i.e., the guard of the second equation in Definition 7.2.3.
Hence, we say that we are working on expressions up to α-conversion (i.e., name conversion), meaning that the names can be consistently renamed in an expression. We make
use of the following convention:
Convention 1. All expressions that differ only with names of binding variables are exchangeable in all contexts.
Hence, the binding variable z for the innermost lambda can be renamed to e.g., w, and
the expression λz. ([x 7→ z](λw. x)) can be reduced to λz. λw. z.
In the call-by-name evaluation strategy, also the leftmost outermost redex is reduced
first, but evaluation is not allowed under lambda. E.g,
(λx. λw. x)((λy. y)(λz. z)) −→
(λw.(λy. y)(λz. z))
Hence, the evaluation stops after the first step because the only available redex is under a
lambda abstraction.
Finally, in the call-by-value evaluation strategy, the argument is first reduced to a
value, followed by a beta reduction of the outermost redex. In the pure lambda calculus,
only lambda abstractions are values. However, we will later in this thesis enrich the
language with more constructs and where other expressions are also values. The same
example as above with the call-by-value strategy evaluates as follows:
(λx. λw. x)((λy. y)(λz. z)) −→
(λx. λw. x)(λz. z) −→
(λw. λz. z)
In this thesis, we are only concerned with enriched variants of call-by-value calculi.
We now formally define the semantics of the lambda calculus with the call-by-value
evaluation strategy using small-step operational semantics. The rules for the operational
semantics are given below:
108
7 Introduction to Functional Programming in MKL
Definition 7.2.4 (Call-by-value operational semantics).
e1 −→ e′1
e1 e2 −→ e′1 e2
(E-APP1)
e2 −→ e′2
v1 e2 −→ v1 e′2
(λx.e) v −→ [x 7→ v]e
(E-APP2)
(E-BETA)
We must also give the definition of a value
v ::= λx.e
(7.2)
i.e., a value is a lambda abstraction. The first two rules are called congruence rules and
the last one computation rule. The former rules are used for “going inside” an expression,
and the last one, the β-rule, reduces (computes) a redex. Note also how the meta-variables
for values make the calculus deterministic. Hence, at most one rule can apply.
7.3
Chapter Summary and Conclusions
We have in this chapter introduced fundamental concepts in functional programming, by
giving examples in our research language MKL. Language constructs presented so far is
available in most standard functional languages, that is, new language constructs in MKL
are presented in the next chapters.
We have also given a short introduction to the lambda calculus, which will be used in
Chapter 10 where we present the core of MKL’s semantics.
8
Modeling in MKL
fundamental construct in an EOO languages is an acausal model (also called noncausal model). Such models can encapsulate and compose both continuous-time
behavior in the form of DAEs or other interconnected components, where the direction of
information flow between the components is not specified.
In functional programming languages, such as Haskell [134] and Standard ML [98],
standard libraries have for a long time been highly reusable, due to the basic property of
having functions as first-class values. This property, also called higher-order functions,
means that functions can be passed around in the language as any other value.
In this chapter, we investigate the combination of acausal models with higher-order
functions. We call this concept higher-order acausal models (HOAMs) .
A similar idea called first-class relations on signals has been outlined in the context
of functional hybrid modeling (FHM) [109]. Giorgidze and Nilsson’s later developments
of this work have focused on efficient JIT compilation and aspects of embedding the
constructs in Haskell [61, 62, 63]. However, that work is still at an early stage regarding
formalizing the semantics. In contrast, our previous work’s main objective has been to
define a formal operational semantics for a subset of a typical EOO language [17]. From
the technical results of our earlier work, we have extracted the more general ideas of
HOAM, which was first published by Broman and Fritzson in 2008 [25]. This chapter
consists of a refinement of that work, where examples have been updated to conform to
the MKL syntax.
In the chapter, we show examples of using HOAMs that in principle1 subsume three
different constructs in Modelica:
A
1 Because the semantics of MKL and Modelica are fundamentally different we cannot say that the constructs
can directly replace each other.
109
110
8 Modeling in MKL
• The Modelica redeclare construct used for replacing sub-models and components in a Modelica model with other models/components (subsumed by passing
models as arguments to other models).
• The Modelica for-equation construct used for creating equations and connecting
several components together (subsumed by using recursive HOAMs).
• The Modelica construct of conditional components used for inclusion/exclusion
of a component depending on a conditional expression (subsumed by using ifexpressions and HOAMs).
An objective of this chapter is to make the basic ideas of higher-order acausal models
accessible both to engineers with little functional language programming background, as
well as to computer scientists with minimal knowledge of physical acausal modeling.
Hence, the chapter is structured in the following way to both reflect the broad intended
audience, as well as presenting the contributions of the concept of HOAMs:
• We give an informal introduction to physical modeling in our research language
MKL (Section 8.1).
• We state a definition of higher-order acausal models (HOAMs) and outline motivating examples. Surprisingly, this concept has not previously been widely explored
in the context of EOO-languages (Section 8.2).
• Finally, we give examples using dynamic data structures together with higher-order
models and discuss polymorphism. (Section 8.3).
8.1
Basic Physical Modeling in MKL
In conventional object-oriented programming languages, such as Java or C++, the behavior of classes is described using methods. However, in equation-based object-oriented
languages, the continuous-time behavior is typically described using differential algebraic
equations and the discrete-time behavior using e.g., conditional equations. This behavior
is grouped into abstractions called classes or models (Modelica) or entities and architectures (VHDL-AMS). From now on we refer to such abstractions simply as models.
Models are blue-prints for creating model instances (in Modelica called components).
The models typically have well-defined interfaces consisting of ports (also called connectors), which can be connected together using connections. A typical property of EOOlanguages is that these connections usually are acausal, meaning that the direction of
information flow between model instances is not defined at modeling time.
111
8.1 Basic Physical Modeling in MKL
(I)
let Circuit =
let e1:Electrical in
let e2:Electrical in
let e3:Electrical in
let e4:Electrical in
Resistor 10. e1 e2;
Capacitor 0.01 e2 e4;
Resistor 100. e1 e3;
Inductor 0.1 e3 e4;
SineVoltage 220. 50. e1 e4;
Ground e4
(II)
model Circuit
Resistor R1(R=10);
Capacitor C(C=0.01);
Resistor R2(R=100);
Inductor L(L=0.1);
SineVoltage AC(VA=220);
Ground G;
equation
connect(AC.p, R1.p);
connect(R1.n, C.p);
connect(C.n, AC.n);
connect(R1.p, R2.p);
connect(R2.n, L.p);
connect(L.n, C.n);
connect(AC.n, G.p);
end Circuit;
Figure 8.1: Figure (I) lists the MKL model definition of a simple electrical circuit,
and (II) shows a Modelica model of the same circuit.
In the context of EOO languages, we define acausal (also called non-causal) models
using the following definition:
Definition 8.1.1 (Acausal Model).
An acausal model is an abstraction that encapsulates and composes
1. continuous-time behavior in the form of differential algebraic equations (DAEs),
and/or
2. interconnected components, where the direction of information flow between components is not specified.
Sometimes, a model has both causal and acausal ports. In such a case we say that the
model is partially acausal.
In many EOO languages, acausal models also contain conditional constructs for handling discrete events. Moreover, connections between model instances can typically both
express potential connections (across) generating direct equality equations and flow (also
called through) connections generating sum-to-zero equations.
8.1.1 A Simple Electrical Circuit
To illustrate the basic modeling capabilities of MKL, the source code of a simple electrical
circuit is listed in Figure 8.1. Part (I) shows the corresponding textual model given in
MKL. For clarity to the readers familiar with the Modelica language, we also compare to
the same model given as Modelica textual code (II).
In the example Circuit, the model is given a name using the let-construct. The
expression defining the model lists four local let-expressions. These expressions define
112
8 Modeling in MKL
Figure 8.2: Graphical model of a simple electrical circuit.
four nodes 2 of type Electrical, i.e., the nodes are defined for the electrical domain.
Below the definitions of nodes, six components are defined. Figure 8.2 shows a graphical
representation of the circuit, including the six components and the nodes e1, e2, e3, and
e4.
Consider the first resistor component using the following line, which contains a call
to the Resistor by passing three arguments using the functional call notation without
parenthesis.
Resistor 10. e1 e2;
The two last arguments state that nodes e1 and e2 are connected to this resistor instance
(compare Figure 8.2 and Figure 8.1). We say that the nodes are connected to the components’ ports. In the same manner, we can see that, e.g., node e4 is connected to the ports
of the VoltageSource, Inductor, and Capacitor instances. Hence, the intuition
is that nodes in a model connect components together. The type Electrical of the
node indicates that we are modeling in the electrical domain and that only ports of type
Electrical can be connected to nodes of the same type. The first argument expresses
that the resistance for this instance is 10 Ohm. In the same way, the first argument states
that the Inductor has inductance 0.1.
Modeling using MKL differs in several ways compared to Modelica (Figure 8.1, part
II). First, models are not defined anonymously in Modelica and are not treated as firstclass citizens. Second, the way in which acausal connections are defined between model
instances differs. In MKL, the connection (in this case the electrical nodes), is created
and then connected to the model instances by giving it as an argument to the creation of
sub-model instances. In Modelica, a special connect-equation construct is defined in
the language. This construct is used to define binary connections between connectors of
sub-model instances. From a user point of view, both approaches can be used to express
acausal connections between model instance. Hence, we let it be up to the reader to
judge what is the most natural way of defining interconnections. However, from a formal
semantics point of view, with regards to HOAMs, we have found it easier to encode
2 Nodes
are similar to what is called terminals in VHDL-AMS.
8.1 Basic Physical Modeling in MKL
113
connections using the ordinary parameter passing style, exemplified here using MKL.
8.1.2 Models and Equation Systems
The main model in this example is the Circuit model. This model contains instances
of other models, such as the Resistor model:
let Resistor R:Real -> p:Electrical -> n:Electrical -> Equations=
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
R *. i = v
In the same way as for Circuit, this model is defined using the let-construct followed
by formal parameters with type annotations. In this Resistor model, the first formal
parameter R of type Real states the resistance of a component. The second and third
formal parameters are the ports of the component, i.e., the connection points. The type
for both formal parameters is Electrical, which is the type of a node in the electrical
domain. Recall that the nodes in model Circuit had type Electrical. Hence,
acausal connections in MKL are simply parameter passing of nodes. Note that these
connections do not state any causality and order of computation. The control flow and
approach to solve the equation system is not defined at modeling time.
The return type given for the resistor model is of type Equations. This is the return
type of any acausal model defined in the language. Hence, when an instance is created
of the Resistor model, the returned value is a system of equations. Several systems of
equations are composed together using the operator ; (recall the use of this operator in
the Circuit model in Figure 8.1). In the next chapter, we go into the details about what
the Equations type actually mean. However, for the purpose of illustrating physical
modeling capabilities, it is enough to view it as an abstract concept representing a system
of equations.
The body of the Resistor model consists of four lines of code. The first two lines
define two new unknown variables i and v. Note that compared to an ordinary letexpression, no value is bound to the variable. Hence, let-expressions without a binding
value are treated as unknowns in the model. These unknowns are then later solved during
simulation.
The third line states an ElectricalBranch. The purpose of the branch is twofold.
First, it is used to bind equations to the unknowns i and v (first and second arguments).
The unknown current i is the current flowing through the component. The unknown
voltage v is the voltage drop over the component, i.e., the potential difference between
the positive port p and negative port n. The third and fourth arguments are the nodes
coming from the ports of the model. The second purpose of the branch equation is for
generating equations conforming to Kirchhoff’s current law. The details of this connection semantics are described and discussed in Section 11.2. However, the intuition of the
ElectricalBranch is that it is path of flow through a component and between two
nodes. From a graph theoretical point of view, we would say vertex instead of node, edge
instead of branch, and graph instead of network. However, we will use the former terminology because it is commonly used in the electrical domain and also in related languages,
such as VHDL-AMS [10].
114
8 Modeling in MKL
The fourth line states an equation describing the continuous-time behavior of the
model. For the Resistor model, it is simply an algebraic equation stating Ohm’s law.
The Inductor model is defined as follows:
let Inductor L:Real -> p:Electrical -> n:Electrical -> Equations=
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
L *. (der i) = v
and similarly, the Capacitor model:
let Capacitor C:Real -> p:Electrical -> n:Electrical -> Equations=
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
C *. (der v) = i
The main difference compared to the Resistor model is that the Inductor and the
Capacitor models contain differential equations, where the i and v variables are differentiated with respect to time using the der-operator. The voltage source model is
defined as follows:
let SineVoltage V:Real -> f:Real ->
p:Electrical -> n:Electrical -> Equations =
let PI = 3.1415 in
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
v = V *. sin(2. *. PI *. f *. time)
The first model SineVoltage specifies a time varying voltage source, by using a sine
function sin with type Real -> Real, and the global time variable time, which
gives the current time in seconds. Note also that we have defined a constant PI using
an ordinary let-expression. The last model in this example Circuit is the Ground
model:
let Ground p:Electrical -> Equations =
let i:Current in
let v:Voltage in
ElectricalRefBranch i v p;
v = 0.
Similarly to what is done in Modelica, the Ground model is modeled by binding a potential voltage variable to zero. The main difference of the Ground model compared to the
other models is that it is using a reference branch equation ElectricalRefBranch
instead of an ElectricalBranch. The reference branch takes only one node as argument, in this case, the node coming from the positive port p. The unknown v gives
the absolute potential value of the node coming from the parameter p. The unknown i
represents the current flowing through the component, which in this case ought to be zero.
The careful reader might now ask what the difference is between the definition of an
acausal model using a let-expression and a higher-order function defined using a letexpression? The answer is: none. Acausal models in MKL are defined and abstracted
8.2 Higher-Order Acausal Modeling
115
using ordinary functions. The difference is that these models contain unknowns defined
by using let-expressions that lack a binding to a value. Moreover, the actual computation
of solving the equations are delayed to a later stage. We will postpone the discussion of
the details of the exact meaning of these constructs to the next chapter, and instead give a
bigger example of higher-order modeling.
Note also that we have as a convention to start ordinary function names with a lowercase letter (e.g., the fact factorial function in Chapter 7) and model names with an uppercase letter (e.g., Circuit or Resistor). Even if both are functions from the language
point of view, we find that this convention clarifies the source code.
8.2 Higher-Order Acausal Modeling
In EOO languages models are typically treated as compile time entities, which are translated into hybrid DAEs during the compiler elaboration phase. We have previously seen
how functions can be turned into first-class citizens, passed around, and dynamically created during evaluation (see Chapter 7). Can the same concept of higher-order functions
semantics be generalized to also apply to acausal models in EOO languages? If so, does
this give any improved expressive power in such a generalized EOO language?
In this section we describe concrete examples of acausal modeling using MKL. However, let us first define what we actually mean by higher-order acausal models.
Definition 8.2.1 (Higher-Order Acausal Model (HOAM)).
A higher-order acausal model is an acausal model, which can be
1. parameterized with other HOAMs.
2. recursively composed to generate new HOAMs.
3. passed as an argument to, or returned as a result from functions.
In the first case of the definition, models can be parameterized by other models. For example, the constructor of an automobile model can take as an argument another model
representing a gearbox. Hence, different automobile instances can be created with different gearboxes, as long as the gearboxes respect the interface (i.e., the type) of the gearbox
parameter3 of the automobile model.
The second case of Definition 8.2.1 states that a model can reference itself; resulting
in a recursive model definition. This capability can for example express models composed
of many similar parts, e.g., discretization of flexible shafts in mechanical systems or pipes
in fluid models.
Finally, the third case emphasizes the fact that HOAMs are first-class citizens, e.g.,
that models can be both passed as arguments to functions and created and returned as
results from functions. Hence, in the same way as in the case of higher-order functions,
generic reusable functions can be created that perform various tasks on arbitrary models,
as long as they respect the defined types (interfaces) of the models’ formal parameters.
Consequently, this property enables model composition to be defined and executed within
3 We refer here to formal parameters when the model is viewed as a function. It is not related to the concept
of parameters in Modelica, which are constants during simulation time.
116
8 Modeling in MKL
the modeling language itself. For example, certain discretizations of models can be implemented as a generic function and stored in a standard library, and then reused with
different user defined models.
Some special and complex language constructs in currently available EOO languages
express part of the described functionality (e.g., the redeclare and for-equation constructs
in Modelica). However, in the sequential sections we show that the concept of higherorder acausal models is a small but very powerful and expressive language construct that
subsumes and/or can be used to define several other, more complex language constructs.
Whether the end user finds this more functional approach of modeling easy or hard depends of course on many factors, e.g., previous programming language experiences and
syntax preferences. However, from a semantic point of view, we show that the approach
is very expressive because few language constructs enable rich modeling capabilities in a
relatively small kernel language.
We will now in the rest of this section exemplify three kinds of uses of HOAM by
giving examples in MKL.
8.2.1 Parameterization of Models with Models
A common goal of model design is to make model libraries extensible and reusable. A
natural requirement is to be able to parameterize models with other models, i.e., to reuse
a model by replacing some of the sub-models with other models. To illustrate the main
idea of parameterized acausal models, consider the following over-simplified example of
an automobile model:
let Automobile Engine:(Rotational -> Equations) ->
Tire:(Rotational -> Equations) ->
Equations =
let r1:Rotational in
let r2:Rotational in
Engine r1;
Gearbox r1 r2;
Tire r2; Tire r2; Tire r2; Tire r2
In the example, the automobile is defined to have two formal parameters; an Engine
model and a Tire model. To create a model instance of the automobile, the model can
be applied to a specific engine, e.g., a model EngineV6 and some type of tire, e.g.
TireTypeA:
Automobile EngineV6 TireTypeA;
If later on a new engine was developed, e.g., EngineV8, a new automobile model instance can be created by changing the arguments when the model instance is created,
e.g.,
Automobile EngineV8 TireTypeA;
Hence, new model instances can be created without the need to modify the definition of
the Automobile model. This is analogous to a higher-order function which takes a
function as a parameter, and somewhat related to a Modelica model with replaceable formal parameters. In fact, because acausal models are abstracted by higher-order functions
in MKL, the same fundamental semantics is used in both cases.
8.2 Higher-Order Acausal Modeling
117
Figure 8.3: A simple mechatronic system with a direct current (DC) motor to the
left and a flexible shaft to the right. The flexible shaft consists of 1 to N elements,
where each element includes an inertia, a spring, and a damper.
In the example above, the definition of Automobile was not parametrized on the
Gearbox model. Hence, the Gearbox definition must be given in the lexical scope of
the Automobile definition. However, this model could of course also be defined as a
parameter to Automobile.
This way of reusing acausal models has obvious strengths, and it is therefore not surprising that constructs with similar capabilities are available in some EOO languages, e.g.,
the special redeclare construct in Modelica. However, instead of creating a special
language construct for this kind of reuse, we believe that HOAMs can give simpler and a
more uniform semantics of an EOO language.
8.2.2 Recursively Defined Models
In many applications it is enough to hierarchically compose models by explicitly defining model instances within each other (e.g., the simple Circuit example). However,
sometimes several hundred model instances of the same model should be connected to
each other. This can of course be achieved manually by creating hundreds of explicit
instances. However, this results in very large models that are hard to maintain and get an
overview of.
One solution could be to add a loop-construct to the EOO language. This is the approach taken in Modelica, with the for-equation construct. However, such an extra
language construct is actually not needed to model this behavior. Analogously to defining
recursive functions, we can define recursive models . This gives the same modeling possibilities as adding the for-construct. However, we have also found it easier to define a
compact formal semantics of the language using this construct.
Consider Figure 8.3 which shows a simple mechatronic model, i.e., a model containing components from both the electrical and mechanical domain. The left hand side of
the model shows a direct current (DC) motor. The electromotoric force (EMF) component
converts electrical energy to mechanical rotational energy.
In the middle of the model in Figure 8.3 a rotational body with Inertia J = 0.2 is
defined. This body is connected to a flexible shaft, i.e., a shaft which is divided into
a number of small bodies connected in series with a spring and a damper in parallel in
between each pair of bodies. Variable N is the number of elements that the shaft consists
of.
118
8 Modeling in MKL
A model of the mechatronic system is described by the following MKL source code.
let MechSys =
let r1:Rotational in
let r2:Rotational in
let r3:Rotational in
DCMotor r1;
Inertia 0.2 r1 r2;
FlexibleShaft 120 r2 r3
If we recall from the previous section, the connection between electrical components was
defined using Electrical nodes. However, in the rotational mechanical domain, the
connection is instead defined by creating Rotational nodes. In the MechSys model,
three such nodes are created. These nodes are used for connecting the DCMotor, the
Inertia and the FlexibleShaft components together.
The most interesting part is the definition of the FlexibleShaft component. This
shaft is connected to the Inertia to the left. To the right, it is connected to node r3, which
is not connected to any other port. Hence, ports always need to be connected to a node,
even if it is a singleton node. The first argument supplied to the FlexibleShaft model
states the number of elements that the shaft should consist of; in this case 120 elements.
Can these 120 elements be described without the need of code duplication? Yes, by
the simple but powerful mechanism of recursively defined models. Consider the following
self-explanatory definitions of ShaftElement:
let ShaftElement flangeA:Rotational -> flangeB:Rotational ->
Equations =
let r1:Rotational in
Spring 8. flangeA r1;
Damper 1.5 flangeA r1;
Inertia 0.5 r1 flangeB
This model represents just one of the 120 elements connected in series in the flexible shaft. The actual flexible shaft model is recursively defined and makes use of the
ShaftElement model:
let FlexibleShaft n:Int -> flangeA:Rotational ->
flangeB:Rotational -> Equations =
if n == 1 then
ShaftElement flangeA flangeB
else
let r1:Rotational in
ShaftElement flangeA r1;
FlexibleShaft (n-1) r1 flangeB
The recursive definition is a standard recursively defined function, where the if-expression
evaluates to false, as long as the count parameter n is not equal to 1. For each recursive
step, a new connection is created by defining r1, which connects the shaft elements in
series. Note that the last element of the shaft is connected to the last argument supplied to
the FlexibleShaft model because the shaft element created when the if-expression
is evaluated to true takes parameter flangeB as an argument.
8.2 Higher-Order Acausal Modeling
119
When the MechSys model is elaborated using our MKL prototype implementation,
it results in a DAE consisting of 1586 equations and the same number of unknowns4. It is
obviously beneficial to be able to define recursive models in cases such as the one above,
instead of manually creating 120 instances of a shaft element.
However, it is still a bit annoying to be forced to write the recursive model definition
each time one wants to serialize a number of model instances. Is it possible to capture
and define this serialization behavior once and for all, and then reuse this functionality?
8.2.3 Higher-Order Functions for Generic Model Composition
In the previous section we have seen how models can be reused by applying models to
other models, or to recursively define models. In this section we show that it is indeed
possible to define several kinds of generic model composition strategies by using higherorder functions. These functions can in turn be part of a modeling language’s standard
library, enabling reuse of model composition functions.
Recall the examples from Chapter 7 of higher-order functions returning other anonymously defined functions. Assume that we want to create a general function, which can
take any two models that have two ports defined (e.g., Inertia or ShaftElement),
and then compose together by connecting them in parallel, and then return this new model:
let composeParallel
model1:(Rotational -> Rotational -> Equations) ->
model2:(Rotational -> Rotational -> Equations) ->
(Rotational -> Rotational -> Equations) =
(fun flangeA:Rotational -> fun flangeB:Rotational ->
model1 flangeA flangeB;
model2 flangeA flangeB)
However, for example, our Spring model does not take two arguments, but three,
where the first one is the value for the particular component (e.g., spring constant for
the Spring model and moment of inertia for the Inertia model). Because models
are higher-order functions and multiple formal parameters are defined using currying, the
solution is basic partial application where the first argument is supplied to the model. For
example, a new function comp that composes a spring and a damper can be defined as
follows:
let comp = composeParallel (Spring 8.) (Damper 1.5)
A standard library can then further be enhanced with other higher-order functions, e.g., a
function that composes two models in series:
let composeSerial model1:(Rotational -> Rotational -> Equations)->
model2:(Rotational -> Rotational -> Equations)->
(Rotational -> Rotational -> Equations) =
(fun flangeA:Rotational -> fun flangeB:Rotational ->
let flangeM:Rotational in
4 Using our elaboration approach, this is approximately half the number of equations generated by using the
Modelica elaboration semantics (2922 equations for the corresponding Modelica model). The main reason is
that our semantics do not need to generate equations for potential variables between connectors. Details of this
elaboration semantics is given in Chapter 11.
120
8 Modeling in MKL
model1 flangeA flangeM;
model2 flangeM flangeB)
Note that this time a new node is created between model1 and model2. Consider now
the following new definition of the ShaftElement:
let ShaftElement =
let comp = composeParallel (Spring 8.) (Damper 1.5) in
composeSerial comp (Inertia 0.5)
This results in the exact same model instance as the one giving before, where the components were connected using node connections. Hence, models can be composed by
either direct node connection, or by utilizing higher-order functions for generic model
composition.
We have now created two simple higher-order functions which compose models in
parallel and in series. However, can we create a function that takes a model M and
an integer n, and then returns a new model where n number of models M have been
connected in series? If this is possible, we do not have to create a special recursive model
for the FlexibleShaft, as shown in the previous section.
Fortunately, this is indeed possible by combining a recursive model (e.g., a recursive
function) and a higher-order function. Consider the following definition of a serialization
function for the rotational domain:
let serializeRotational
n:Int -> model:(Rotational -> Rotational -> Equations) ->
(Rotational -> Rotational -> Equations) =
let recmodel n:Int -> flangeA:Rotational ->
flangeB:Rotational -> Equations =
if n <= 1 then
model flangeA flangeB
else
let nodeNew:Rotational in
model flangeA nodeNew;
recmodel (n-1) nodeNew flangeB
in
(fun flangeA:Rotational -> fun flangeB:Rotational ->
recmodel n flangeA flangeB)
The main function definition serializeRotational contains a local function definition recmodel. A closer look at the latter function shows that it is almost identical
to the definition of model ShaftElement. The main difference is that in recmodel,
instances are created from the variable model, which is the second parameter of the
function serializeRotational.
The last part of the main function returns a curried function representing a rotational
model of two ports (flangeA and flangeB). The body of this function is calling
recmodel, resulting in a composed model with n elements in series.
Now, we can once again define the mechatronic system given in Figure 8.3, but this time
by using function serializeRotational:
let MechSys2 =
let r1:Rotational in
8.3 Dynamic Data Structures and Polymorphism
121
let r2:Rotational in
let r3:Rotational in
DCMotor r1;
Inertia 0.2 r1 r2;
(serializeRotational 120 ShaftElement) r2 r3
Even if the serialize function might seem a bit complicated to define, the good news is that
such functions usually are created by library developers and not end-users. Fortunately,
the end-user only has to call the serialize function and then use the newly created model.
8.3 Dynamic Data Structures and Polymorphism
We have in the previous section created a flexible function for connecting series of models
in the rotational domain. However, how can we connect a list of models in series, which
are not configured in the same way, i.e., do not have the same inertia or spring constant?
Moreover, do we need to create a new version of e.g. the serialization functions for each
physical domain? These questions are the topics for this section.
8.3.1 Model Composition over Lists of Models
Let us a assume that we want to model the flexible shaft again, but with a few hypothetical
requirements:
• The shaft element should be modeled in the same way as in the previous section,
with the difference that the inertia J can be different for each shaft element.
• The first element should have inertia 0.5 and then each element should have an
increased intertia of 0.2.
• An inertia component of an element should only exist if the expected inertia is
greater than 5.0, otherwise it should not be inserted in the model.
• There should be no shaft elements with inertia larger or equal to 10.0, i.e., this states
the termination condition for the generation of the shaft elements.
To start with, we define a type synonym for a rotational model with two ports:
type RotModel = Rotational -> Rotational -> Equations
The idea would be to create a list of shaft element models which is valid for the above requirements and then to connect all these models in series. A general serialization function
over a list of models in the rotational domain can be defined as follows:
let serializeList models:[RotModel] -> RotModel =
let serialize flangeA:Rotational -> flangeB:Rotational ->
models:[RotModel] -> Equations =
match models with
| [m] -> m flangeA flangeB
| m::ms ->
let flangeM:Rotational in
122
8 Modeling in MKL
m flangeA flangeM;
serialize flangeM flangeB ms
| [] -> error "illegal to serialize an empty list"
in
(fun flangeA:Rotational -> fun flangeB:Rotational ->
serialize flangeA flangeB models)
A local function is performing the recursion over the list. The list is deconstructed using
pattern matching, and returning a composed new model, where all model elements are
connected in series.
To meet the requirements, one way could be to create a new shaft element, which is
parameterized by the inertial J:
let ShaftElement2 J:Real =
let comp = composeParallel (Spring 8.) (Damper 1.5) in
if J >. 5. then composeSerial comp (Inertia J) else comp
Note that this variant of the shaft element is only adding an Inertia instance, if J is larger
than 5. This selection is performed with a standard if-expression.
We also need to generate the list of shaft elements, where the inertia is increased with
0.2 for each element. This is straightforward using a recursive function:
let genElemList J:Real -> incrJ:Real -> maxJ:Real -> [RotModel] =
if J <. maxJ then
(ShaftElement2 J)::(genElemList (J +. incrJ) incrJ maxJ)
else []
The first parameter is the inertial, the second the increment value and the third the max
value, i.e., deciding when to finish the recursion.
Finally, we create an instance of this new flexible shaft inside the mechatronic system:
let MechSys3 =
let r1:Rotational in
let r2:Rotational in
let r3:Rotational in
DCMotor r1;
Inertia 0.2 r1 r2;
(serializeList (genElemList 0.5 0.2 10.)) r2 r3
8.3.2 Parametric Polymorphism
We have in the previous section illustrated some of the modeling flexibility and expressiveness of being able to use higher-order models together with data structures such
as lists. However, so far we have modeled all components within a specific domain;
in this case the mechanical rotational domain. For example, recall that the function
serializeList was specially defined for the RotModel type
type RotModel = Rotational -> Rotational -> Equations
where the ports were Rotational nodes. Would it not be good to be able to create
one function that could take models from any physical domain and connect such models
8.4 Chapter Summary and Conclusions
123
in series? The solution would be to incorporate parametric polymorphism in the language, i.e., to have type variables in the let-expression. For example, a generic variant
of serializeList could look like
let serializeList models:[’a -> ’a -> Equations] ->
(’a -> ’a -> Equations) =
...
where the type variables are denoted as identifiers prefixed by a single-quote ’. However,
the current version of our experimental platform is monomorphic with regards to types
and therefore such a definition as above is not allowed. At first glance, this extension
seems straightforward to incorporate into the language, but a more in depth study needs
to be performed to see how it interacts with the other constructs of the model lambda
calculus, which is presented in Chapter 10. We leave as future work the study of incorporation of parametric polymorphism into the language.
8.4 Chapter Summary and Conclusions
We have in this chapter given a basic introduction of the fundamentals of mathematical
modeling in MKL. In particular, we study and give examples of how the concept of higherorder acausal model (HOAM) can be used for modeling.
We conclude that HOAMs can be used to express several of the language constructs
available in Modelica, such as for-equations, redeclare-constructs, and conditional
components. We have also shown how HOAMs can be used together with lists for flexible
modeling. However, it is to early to draw any general conclusions that this modeling
technique is easy to use from a user perspective.
124
8 Modeling in MKL
9
Intensional Analysis of Models
metaprogramming environments and systems, metaprograms manipulate, transform
and analyze object programs. Metaprograms can, for exampl,e be compilers, theorem
provers, transformation systems, partial evaluators, and analyzers. The aim of metaprograms can be to increase the expressive power of a system and/or to increase the performance of systems.
I
N
Programming languages capable of intensional analysis of code are program analyzers, i.e., metaprograms that inspect and analyze an object program. Extensional metaprogramming languages are on the other hand languages that only generate new programs
using information available in the metaprogram.
Designing and implementing model libraries for different domains often requires deep
knowledge of the mechanisms of the underlying language, as well as implementation details of the used compiler or software tool. Mathematical models include equations of
different forms. The system of equations in such models can be inspected and analyzed
in several ways and for different needs. In this chapter, we introduce the idea of using
intensional analysis of mathematical models, i.e., the possibility for a function to inspect
and analyze the equation system of the model. The programming is homogeneous, meaning that the program manipulates the models created in the same language. The chapter
is organized as follows:
• We explain the concept of models, unknowns, and model types of MKL (Section 9.1).
• We describe, by giving several examples, how pattern matching can be used for
intensional analysis of models (Section 9.2).
125
126
9.1
9 Intensional Analysis of Models
Models and Unknowns
In the previous chapter, we introduced variables that are both algebraic and appear differentiated, e.g., recall the model definition of capacitor:
let Capacitor C:Real -> p:Electrical -> n:Electrical -> Equations=
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
C *. (der v) = i
In the model, we have defined two unknown variables: i of type Current and v of type
Voltage. We say that these variables are binding unknowns because they are not bound
to any explicit values by the let-expressions. The unknown v appears differentiated
(expression (der v)), while i does not and is therefore an algebraic variable.
From a modeling point of view, one might expect that the der operator and the definitions of Current and ElectricalBranch are part of the MKL language. However,
they are not. Instead these construct are defined in MKL standard libraries.
9.1.1 Unknowns
The fundamental construct for mathematical modeling in MKL is the concept of unknown. Unknowns are defined using the syntax
let x:T in e
where x is the variable bound to the unknown, T the type of the unknown and e the
expression where x appears bound.
Unknowns are values and first-class citizen, i.e., they can be passed around as any
other value. Note that this is why we say that the variable x is bound to an unknown, i.e.,
an unknown is created when the let-expression is evaluated.
9.1.2 Model Type
The concrete syntax of types in MKL is defined by the following grammar:
T ::= Int | Real | Bool | String | T ->T | () |
[T ] | (T1 , . . . ,Tn ) | Set T | T =>T | {T } |
<T > | <>
Types <T > and <> are called model types. Type <T > is a specific model type and said to
be a T -model type. For example, <Int> is an integer model type and <Real -> Real>
is a function model type. Type <> is called the any model type. The intuition is that a
value of a model type is a mathematical model, i.e., it includes unknowns and equations.
From a modeling point of view, the terms unknown and variable are often used with
no difference in their meaning. However, from our language design point of view, they
are different concepts.
127
9.1 Models and Unknowns
Definition 9.1.1. An unknown is the value that is created by evaluating a let-expression
of form let x:T in e. The new unknown will be bound by x and substituted in expression e.
Unknowns are here defined to be values (the unknown value) and can never be bound to
another value, while variables are bound within function abstractions and can be substituted by another value.
An unknown is always of a model type. When binding an unknown to a variable using
a let-expression, the type is syntactically checked. For example, expression
let x:<Real> in x
defines x as a Real model type. Now, consider the expression
let x:<Real> in
x +. 1.
that is a model of type <Real>. The add operator +. cannot compute the result of the
addition because x is unknown.
During type checking of the expression, the type checker checks if either of the
operand expressions are of a model type. If this is the case, the operand that was not
a model is embedded into a new expression, the model value expression 1:
val e
where e is the expression that after evaluation will be a value. The value expression has
two purposes. First, it turns the type of an expression e of type T into a model, where
expression val e has type <T >. Secondly, the type T is internally tagged (not visible
to the user) to the expression and can later be used to match the type of the value during
intensional analysis.
This expression can be explicitly given by the user, for example in
let x:<Real> in
x +. (val 1.)
where both x and expression val 1. are explicit model types. In both examples, the
operands are models, where in the former the val expression was inserted by the type
checker, while in the latter case it was explicitly stated by the user.
The add operator is itself a function, which is defined in the standard library base.mkl
(see Appendix D.1) as
let (+.) : Real -> Real -> Real = @@real_add
The line states that a prefix operator (+.) takes two arguments of type Real (curried
form) and returns a Real. The actual operation is performed by the built-in function
@@real_add, which has @@ symbols prefixed to distinguish it from other user defined
identifiers. The operator can be used as either an infix operator e1 +. e2 or as a prefix
operator (+.) e1 e2 .
1 The explanation given in this chapter is informal and somewhat simplified. Details are given in the next
chapter.
128
9 Intensional Analysis of Models
The type checker has a similar procedure for the function value itself, as for its arguments. If both arguments are of model type, the function value is embedded into a val
expression. Hence, our expression will, after the type checking phase, have the form
let x:<Real> in
(val (+.)) x (val 1.)
when we write the add operator in prefix form.
9.1.3 Models as Data Structures
The procedure informally described in the previous section, is related to, but different
from binding-time analysis (BTA) , used in offline partial evaluators [66, 80]. During
BTA, it is determined, given some static input data, if expressions in a program can be
safely evaluated statically (at compile time) or if the computation of the expression must
be delayed until runtime. However, for our translation steps performed during type checking, decisions are made regarding which expressions cannot be evaluated at runtime. No
evaluation is performed statically at compile-time (in the context of model types). Consider the following slightly larger expression:
let y = 2. in
let x:<Real> in
x +. 3. *. y
After the translation phase during type checking, the program is
let y = 2. in
let x:<Real> in
(val (+.)) x (val ((*.) 3. y))
Hence, operator (+.) itself is embedded into a val-expression, but in the case of the
multiplication, the whole expression ((*.) 3. y) is embedded. Why the difference?
The answer lies in the type returned by the type checker. For the operator (+.), its
second operand needs to be a model because the unknown x is a model by definition.
However, in the case of (*.), both arguments have type Real, i.e., they are not models.
Hence, that expression can be safely evaluated during runtime.
The above example is what can be entered as an MKL program, but internally in the
compiler, a different operator is used for application, called model application. The reason
is that the application should be treated as data, i.e., the computation should not be carried
out directly. The model application is here denoted with the infix @ symbol:
let y = 2. in
let x:<Real> in
((val (+.)) @ x) @ (val ((*.) 3. y))
An expression e1 @ e2 , a model application of e1 to e2 can from a dynamic semantics
point of view be considered as a tuple holding a pair of expressions. Hence, the model
translation creates a data structure from an expression, so that operations are not unsafely
performed on unknowns. The result of evaluating the above expression is
let x:<Real> in
((val (+.)) @ x) @ (val (6.))
9.2 Intensional Analysis of Models
129
Hence, sub-expressions that are safe to evaluate can be evaluated, but expressions containing unknowns are translated into data structures.
9.2 Intensional Analysis of Models
Intensional analysis, in the literature of metaprogramming languages, is referred to as the
ability of the language to observe the structure of the code and its decomposition [129].
The information gathered during the analysis can then be used to synthesize a result.
In the case of our mathematical modeling aims, the purpose would be to observe and
inspect the equation system, symbolically manipulate it (e.g., symbolic differentiation),
and solve the equation system. Alternatively, the system of equations can be analyzed and
then translated into another form, e.g., compiled into another target language.
In the following section we show how intensional analysis can be performed on models in MKL, i.e., on expressions of a model type. In this section we explain the syntax
and semantics informally from a programmers point of view. Hence, we will be using the
high-level constructs (e.g., pattern matching) which are then translated into more primitive constructs for the core of the language. In Chapter 10 we explain the core language
formally.
9.2.1 Pattern Matching on Models
In the previous section we stated that models are data structures which can include unknowns. To be able to inspect the model we need to deconstruct the data structure. This
can be performed with pattern matching on models. A model can be built up of three
kinds of elements:
• Unknown. An unknown is the value that is created by a let-expression of form
let x:T in e.
• Model Application. A value v1 applied to another value v2 , where the application
is treated as data.
• Model Value. The expression val v, which embeds a value v.
The syntax of patterns for deconstructing models are as follows:
p ::= uk :T | p1 p2 | val x:T | x
where x is a pattern variable and T represent types. The pattern for unknowns uk :T
matches if the matching value is an unknown and was defined with a type that is equal
to T . Note that you can only test if an unknown match with a specific type, you cannot
extract the type. The pattern for model applications, written as an application p1 p2 ,
consists of two patterns. Hence, it is possible to nest these model application patterns2 .
2 Note that we did not use the @ symbol for model application in patterns. This symbol was only used in the
previous section to emphasize the difference of applications and model applications when they are stored in an
internal form in the program.
130
9 Intensional Analysis of Models
The pattern matches the matching value if it is a model application. The last pattern for
model values val x:T matches if the matching value is a model value and the type of
the value embedded in the model value is consistent with type T . In such case, pattern
variable x is bound to the embedded value. The last pattern x is the pattern variable.
Consider now the following simple model of an expression with two unknowns:
let M
let
let
let
x
=
k = 2. in
x:<Real> in
y:<Real> in
+. 3. *. y *. (x +. k *. 4.)
We would now like to analyze model M and create a function that returns all constants
with type Real:
let constReal m:<> -> acc:[Real] -> [Real] =
match m with
| m1 m2 -> constReal m2 (constReal m1 acc)
| val v:Real -> v::acc
| _ -> acc
The function constReal takes as input a model m, an accumulator3 list acc, and returns a list of constants found in the model. The expression to be matched is m. In the
first case, a pattern for a model application is matched. In such a case recursive calls are
made both with m1 and m2 as arguments. Parameter m has type any model <>, making
it possible perform the recursive call regardless of the specific model type of the supplied
argument. The accumulator list acc is used for storing/accumulating (through v::acc)
all constants that are found, and is therefore threaded through the recursion. If the matching value is not a model application, but a model value, case two applies. Moreover,
the matching case checks that the type of v is Real. In such a case, v is added to the
accumulator list. Finally, if none of the other cases apply, the accumulator list is returned.
If the expression constReal M [] is evaluated, we get the list [8.,3.]. We
supply an empty list as the second argument to constReal. The first thing to notice
is that the model application could be used to traverse the whole model. The reason is
that all operators, including the primitive operators on basic types, are represented as
curried functions. In the second case, model values are matched where the type of the
embedded value should be Real. The second thing to notice is that because we know
that the embedded value has type Real, we can use it in a type-safe way for further
computation. The third observation to be made is that we only get a list of two elements,
but the model contains three constants, 3., 4., and 2.. The latter was bound by variable
k. The reason is that the model translation during type checking only converts the whole
expression k *. 4. into a model value. Hence, when the expression M is evaluated, k
will be substituted by 2. and the embedded model value will be computed to 8..
Consider now another function for pretty-printing the model, i.e., for creating a string
representation of the model:
let pprint m:<Real> -> String =
match m with
3 An
accumulator list is a formal parameter used to accumulate results during recursive calls of the function.
9.2 Intensional Analysis of Models
|
|
|
|
131
e1 +. e2 -> "(" ++ (pprint e1) ++ " +. " ++ (pprint e2) ++ ")"
e1 *. e2 -> (pprint e1) ++ " *. " ++ (pprint e2)
val v:Real -> real2string v
uk:<Real> -> "uk"
The function pprint takes a model m as input and returns a pretty-printed String. The
first two cases match the infix versions of operators +. and *.. The infix representation of
the pattern makes the rule more readable, but is actually just syntactic sugar for the prefix
pattern rule used in combination with a when pattern guard. For example, the second case
is equivalent to:
| op e e2 when op == (*.) -> (pprint e1) ++" *. "++ (pprint e2)
where the pattern is a nested model application pattern. The third case in the matchexpression in function pprint matches a model value and converts the embedded value
into a string. Note that we can safely use v in a context where expressions of type Real
are expected because the type checker guarantees that the embedded type is of type Real.
In the last line, we match that the unknown should have type <Real>. If none of the cases
matches, a runtime error will be generated.
9.2.2 Analyzing Systems of Equations
We are primarily interested in mathematical models consisting of systems of equations.
Let us consider the following classic example:
let LotkaVolterra =
let growthRateRabbits = 0.04 in
let deathRateRabbits = 0.0005 in
let deathRateFoxes = 0.09 in
let efficiencyGrowthFoxes = 0.1 in
let rabbits:Population in
let foxes:Population in
Init rabbits 700.;
Init foxes 10.;
der(rabbits) = growthRateRabbits *. rabbits -.
deathRateRabbits *. rabbits *. foxes;
der(foxes)
= efficiencyGrowthFoxes *. deathRateRabbits *.
rabbits *. foxes -. deathRateFoxes *. foxes
This is a simple form of biological model modeling the population dynamics of an ecological system. The model, called Lotka-Volterra after its inventors, models a predator-prey
relationship, where the predators are foxes and the prey animals are rabbits. The model
given in this example is a translation of the model described by Fritzson [51]. At the
top of the model, a list of constants is given. The last two let-expressions define two
unknowns rabbits and foxes, both of type Population, which is just a type alias
type Population = <Real>
for making the model more readable.
At the bottom of the model, we have two differential equations. Both of the variables
rabbit and foxes appear differentiated, and the differentiated variables both appear
132
9 Intensional Analysis of Models
on the left hand side of the equations. Hence, we have an explicit ODE in state-space
form. To solve the initial value problem, we need to define initial values for the state
variables. This is expressed with the two Init declarations, where for example the
variable rabbit is given the initial value 700..
The MKL language in itself does not know about the concepts of derivatives, initial values, and equations. These are all defined in a program or model. The following
definitions are a selection from the definitions given in the MKL standard library file
modeling.mkl (See Appendix D.2 for a full listing). The type definition
type Eqs
defines a new pseudo type called Eqs. We call it a pseudo type because there is nothing
on the right hand side of the type definition, i.e., there are no constructor or alias defined
for pseudo types. It is only used for type checking models. Because models have model
type, we need to define a model type of Eqs.
type Equations = <Eqs>
The intuition is that Equations is the type of system of equations (one or more equations). This is also the standard return type from a model abstraction, i.e., the result of a
model instantiation is an equation system (compare the electrical and mechanical models
described in Chapter 8).
The next four lines lists the constructs for defining an equation system.
let
let
let
let
Eq : <Real -> Real -> Eqs>
EquationSysNode : <Eqs -> Eqs -> Eqs>
(=) : <Real -> Real -> Eqs> = Eq
(;) : <Eqs -> Eqs -> Eqs> = EquationSysNode
The first definition defines an unknown called Eq which is of function model type. The
function takes two arguments of type Real as input and returns an equation system.
The second unknown is a composition operator for the equation system. An equation
system will internally be stored as a tree of equations, using the EquationSysNode
as the nodes in the tree. The leaves will be the equations. Note how the types define the
relationships.
The last two lines define prefix and infix operators for the equation = and composition
; operators for creating systems of equations. These infix operators are also what is used
when defining models.
The derivative operator der is defined as follows:
let der : <Real -> Real>
i.e., it is an unknown function taking a Real as input and return a Real. Sometimes it is
convenient to use the independent variable time explicitly in the model. For example, in
the previous chapter, we defined model SineVoltage, which uses the time variable.
Time is also an unknown and defined as follows:
let time : <Real>
Finally, we define how a model can be given initial values:
let Init : <Real -> Real -> Eqs>
let InitGuess : <Real -> Real -> Eqs>
9.2 Intensional Analysis of Models
133
The first Init constructor is intended to define an initial condition, where the user states
that it must be initialized to this value (i.e., fixed = true in Modelica). The second
constructor InitGuess should be used when the initial value is only a guess value, i.e.,
as starting point for the solver to search for a consistent initial value.
The first thing to notice about all these definitions is that they define new unknowns.
Hence, the concept of unknown has a very broad use in MKL. It is used both for modeling
unknowns in the ordinary mathematical sense in equations, but also used as a constructor
for expressions. Note also that the actual semantics of the meaning of these definitions
are not defined here, but is defined by the analysis functions that inspects the model.
Now, let us analyze the model. Our first example task is to count the number of
equations and the number of unknowns that an instance of a model contains.
Starting with counting the number of unknowns, we need to count the number of
unique unknowns, not the number of times unknowns appear in equations. We create a
type alias for the set of unknowns:
type UkSet = (Set <Real>)
Our task is now to define a function which takes a system of equations of type Equations
as input and return a value of type UkSet:
let unknowns eqs:Equations -> UkSet =
let get e:<> -> acc:UkSet -> UkSet =
match e with
| e1 e2 -> get e2 (get e1 acc)
| ’time -> acc
| uk:<Real> -> Set.add e acc
| _ -> acc
in get eqs (Set.empty)
The function unknowns traverses the model using model application patterns. Each
time it finds an unknown, the matching value e, which in this case is the unknown of type
<Real> is added to the set. Because it is a set, there are no duplications of elements.
There are two new observations to be made in the example.
The first one is the pattern case with ’time. The pattern syntax ’e is a syntactic
sugar for matching against an expression. Hence, the line with ’time is equivalent to
the following line
| e when e == time -> acc
The rationale for having the time case is that time is also defined to be an unknown of
type <Real>. Because we do not want to include the independent variable time in the
set of unknowns, it is excluded by the match case.
The second observation in the example is that the first parameter e of the get function
has type <>. Recall that this was defined to be the any model type, which has the meaning
that it is type consistent with all other model types. For example, the get function, can
be applied to any argument, as long as it is a model type. This introduces dynamic types
of models within the statically typed language. The approach is inspired by Abadi et.
al.’s [1] work on dynamic typing in statically typed languages, as well as the work on
gradual typing by Siek and Taha [132, 133]. The intuition of the type consistency relation
is that a type <> is type consistent with <> or <T >, for any type T . A type <T1 > is type
134
9 Intensional Analysis of Models
consistent with another type <T2 > iff T1 and T2 are type consistent. A formalization of
this type consistency relation will be given in Chapter 10.
The number of unknowns can then be computed by taking the size of the unknown
set:
let noUnknowns eqs:Equations -> Int =
Set.size (unknowns eqs)
The computation of the number of equations is more direct:
let noEquations eqs:Equations -> Int =
match eqs with
| e1 ; e2 -> (noEquations e1) + (noEquations e2)
| e1 = e2 -> 1
| _ -> 0
In this function we are not traversing any model application, we are only moving down in
the tree of equations. By also matching on the equation using infix notation, we exclude
all other relations that have type <Eqs>, e.g., Init-equations.
By supplying the LotkaVolterra model as argument to both of the noUnknowns
and noEquations functions we get the result 2 for both the number of unknowns and
the number of equations.
Are these functions for calculating the number of unknowns and the number of equations only valid for such small example models as LotkaVolterra? No, they can actually handle arbitrary models, as long as the model is defined using the same primitives
for equations etc. By calling these functions on the elaborated variant of the MechSys
model described in the previous chapter, we get the result of 1586 equations and 1586
unknowns, which are the expected results.
The second and last example in this section for illustrating the idea of intensional
analysis of models is to define a function that extracts a mapping between unknowns and
their defined initial values. We start by defining a type alias for an initial value mapping
between unknowns and initial values:
type InitValMap = (<Real> => Real)
The function for extracting the initial values are defined as follows:
let initValues eqs:Equations -> InitValMap =
let get eqs:Equations -> acc:InitValMap -> InitValMap =
match eqs with
| e1 ; e2 -> get e2 (get e1 acc)
| Init x (val v:Real) -> Map.add x v acc
| _ -> acc
in get eqs (Map.empty)
The local function get takes as its second argument an accumulator map, which is a
mapping that will accumulate a binding each time the Init expression is matched. The
function definition is straightforward and should be self describing. Also note that we are
using a nested pattern for the Init case, from which the embedded value v of the model
value is extracted.
9.3 Chapter Summary and Conclusions
135
9.3 Chapter Summary and Conclusions
In this chapter we gave a short introduction to the ideas of intensional analysis of models
in MKL. We will in both Chapter 11 and 12 give larger examples for showing the approach
of intensional analysis of models.
We showed in a few examples that the language is expressive for traversing the model
structure. This expressiveness is mainly due to the flexibility of having dynamic types for
models, i.e., that a type of a model does not have to be specific, it could be <>.
Regarding language safety, the model type concept in MKL requires that types must
be used when modeling. Hence, the MKL interpreter can type check and report errors in
models, even if the constructs are user defined. This enables early and explicit feedback of
modeling errors. For example, if the user tries to insert an equation inside an expression,
e.g. (3. = 2.) +. 4. the type checker will report an error. Hence, at the modeling
level, the type requirements are strict. However, for analyzing the model, we have favored
expressiveness.
136
9 Intensional Analysis of Models
10
Semantics of MKL
have in previous chapters informally described the syntax and semantics of MKL.
In this chapter we formalize both the static and the dynamic semantics for a core
of the MKL language.
We present three different languages. The language λ<> is the source language corresponding to a core of MKL. An expression in λ<> can be lifted to an intermediate language
λ<>
L , meaning that selected expressions are lifted into models. The reason for model lifting
is, as explained in the previous chapter, to create data structures of models that can later
be inspected and analyzed. The language λ<>
L can be used for evaluation, but is not technically sufficient for proving type safety. Hence, we define a second intermediate language
λ<>
LC where type casts are inserted. We prove soundness of the translation between the
intermediate languages, the usual progress and preservation lemmas for λ<>
LC , and finally
type safety for λ<> . The chapter is structured as follows:
W
E
• We describe the abstract syntax for λ<> and λ<>
L respectively (Section 10.1).
• We state the type system for λ<> , rules for lifting expressions to models, as well as
a type consistency relation used for comparing types. (Section 10.2).
• We prove soundness of model lifting and cast insertion, as well as giving a type
system and operational dynamic small-step semantics for λ<>
LC . (Section 10.3).
• We prove type safety for λ<> (Section 10.4).
• Finally, we discuss different extensions to the core language λ<> (Section 10.5).
10.1 Syntax
Consider the abstract syntax for λ<> that is summarized in Figure 10.1. The metavariables x and y range over X, a countable set of names. The meta-variable e ranges
137
138
10 Semantics of MKL
Variables
Unknowns
Constants
Expressions
x, y ∈ X
u∈U
c∈C
e
::=
Deconstruct patterns
Values
Ground Types
Types
d
::=
v
::=
γ ∈G
τ
::=
x | λx : τ.e | e e | c |
u : τ | ν(τ ) | e @ e | val e : τ | decon(e, d, e, e)
uk : τ | x @ x | val x : τ
λx : τ.e | c | u : τ | v @ v | val v : τ
γ | τ → τ | <τ > | <>
Figure 10.1: Abstract syntax for λ<> and λ<>
L
over the set of expressions Expr and τ ranges over the set of types Types. We use subscripts for denoting different expressions or types, e.g., e1 and e2 represent two different
expressions.
The first four expressions are standard. The expression x is a free variable and lambda
abstraction λx : τ.e binds variable x of type τ in e. We use the lambda notation here, which
has the same meaning as MKL’s concrete syntax for anonymous functions that is defined
with the fun keyword. The expression e1 e2 is application and c ∈ C a constant. The
set of constants C is the union of the set of boolean values {true, false}, the set of
integers, the set of reals (represented as floating-point values), the set of strings, and the
set of primitive functions.
The next five expressions are new for λ<> . The aim of the language is to be able
to express mathematical models and to inspect a models’ structure. Hence, the concept
of unknowns is central. The first expression u : τ is an unknown u tagged with type
τ . The set U is defined as the set of all unknowns. Unlike e.g., logic variables in logic
programming languages, unknowns in MKL cannot be bound to values. Instead, they are
used to build up the data structure of a model that can be deconstructed at a later stage.
To simplify λ<> compared to MKL, we define an expression ν(τ ) (pronounced “new”),
which creates an unknown expression u : <τ > when evaluated. In MKL, unknowns are
constructed using let-expressions of the form let x:T in e. Hence, we define the
following derived form:
let x:<τ > in e ≡ (λx : <τ >.e)ν(τ )
(10.1)
The expression e @ e is a model application, which is typed as a function, but is never
applied. From a runtime perspective a model application can be seen as a tuple with two
elements.
The expression val e : τ is a model value that embeds the expression e of type τ . We
call this a model value because e must be closed and is evaluated to a value before it can
be extracted from val e : τ .
The expression decon(e1 , d, e2 , e3 ) is a deconstructor of models. The value after
evaluating e1 is the value to be deconstructed and matched against the deconstruction
pattern d. We choose the letter d for patterns instead of p to avoid confusion with patterns
139
10.2 Type System and Model Lifting
in match expressions. The expression e2 is returned on a successful match and e3 on a
unsuccessful match.
Deconstructor patterns can have the following shapes: uk : τ for unknowns, x @ x for
matching model application, and val x : τ for matching model values. The variable x is
a pattern variable and τ a type tag1
The meta-variable v ranges over the set of Values, where Values ⊆ Expr 2 . Lambda
abstractions, constants, and unknowns are always values. The language is using weak
reduction with a call-by-value evaluation strategy and therefore variables are not values.
A model application v @ v is a value if its sub-expressions are values. A model value
expression val v : τ is also defined to be a value, if its sub-expression is a value.
10.2 Type System and Model Lifting
In this section we describe the type system for λ<> and how expressions are lifted to
models, by translation to λ<>
L . We start by considering types and how they are compared.
Recall the syntax definition of types in Figure 10.1. There are two standard types and
two new types for this language. The meta-variable γ ranges over all ground types G,
which includes boolean, integer type etc. The type τ → τ is the standard function (arrow)
type.
The two new types <τ > and <> are both model types. The former is the specific
model type , stating that this model is of type τ . The latter is called the any model type
because a value with that type can be any model. The intuition of the type system is
that it introduces dynamic typing for models in a statically typed functional language. To
deconstruct a model, the explicit deconstruct expression decon must be used.
A first attempt of defining a type system for model types would be to introduce a
subtyping relation between specific model types and any model types. In such a case,
type <> represents the top model type. The subtyping rules for such a system could be as
follows:
τ <: τ ′
Subtyping rules
γ <: γ
<τ > <: <>
τ1 <: τ2
<τ1 > <: <τ2 >
τ3 <: τ1 τ2 <: τ4
τ1 → τ2 <: τ3 → τ4
A type system would then include the usual rule of subsumption:
Γ ⊢ e : τ1 τ1 <: τ2
Γ ⊢ e : τ2
1 Note that deconstructor patterns are not nested for the reason of making the core language as simple as
possible. However, match-expressions in full MKL can contain nested patterns. These match-expressions
are then translated during pattern compilation to primitives for deconstructing values, where decon is used for
deconstructing models.
2 In this chapter, we only define an operational semantics for λ<> . The languages λ<> and λ<> are only
LC
L
used as translation steps for proving type safety. Consequently, values are strictly not necessary to define at this
<>
stage. However, we define a big-step semantics for λL in Appendix C that motivates the inclusion of values.
140
10 Semantics of MKL
Now, assume we have a function f : <Int> → <Int> and a constant c : <Int>. Then,
an expression
(λx : <>.x)c
has type <> in such a subtyping system. However, an expression
(λx : <>.f x)c
is not typeable because x has type <> which is a supertype and not a subtype of <Int>,
which is the function f ’s argument’s type. We argue that this typesystem is too restrictive
and does not give the flexibility of dynamic typing of models. Instead, we choose to use
a more flexible approach with type consistency.
10.2.1 Type Consistency
We adopt the idea of replacing type equality in type checking rules with the type consistency relation ∼. This idea was pioneered by Siek and Taha [132, 133] in the context of
gradual typing. The intuition of the consistency relation in our language is that ground
types shall be compared with equality, while the type <> is consistent with both <τ > and
<> for some type τ . For example:
<Int> ∼ <>
<Int->Real> ∼ <Int->Real>
<> ∼ <Bool->Real>
Int 6∼ <>
<Real>->Real ∼ <>->Real
Real-><> 6∼ <>->Real
Real 6∼ Bool
Note the difference from gradual typing [133] that the type <> is only consistent with
other model types, not with any other type.
Before we define type consistency, we define a restriction operator as follows:
τ kτ
Restriction
<τ > k<>
<τ1 > k<τ2 >
τ11 → τ12 kτ21 →τ22
τ1 kτ2
=
=
=
=
<>
<τ1 kτ2 >
τ11 kτ21 → τ12 kτ22
τ1
if τ1 6= <τ3 > and τ1 6= τ11 → τ12
for some τ3 , τ11 , and τ12
We can now define type consistency:
Definition 10.2.1 (Type Consistency).
Two types τ1 and τ2 are consistent, written τ1 ∼ τ2 iff τ1 kτ2 = τ2 kτ1 .
Proposition 10.1 (Properties of ∼)
The restriction operator has the following basic properties:
(a) ∼ is reflexive.
141
10.2 Type System and Model Lifting
(b) ∼ is symmetric.
(c) ∼ is not transitive. For example
<Int> ∼ <> and <> ∼ <Real> but <Int> 6∼ <Real>.
(d) τ1 ∼ τ2 iff <τ1 > ∼ <τ2 >.
(e) If <> ∼ τ then τ = <> or ∃τ ′ .τ = <τ ′ >.
(f) If <> ∼ τ and τ ∼ τ ′ then <> ∼ τ ′ .
(g) If τ ∼ <τ ′ > then τ ∼ <>.
Note that property (e) is a compact way to test if a type is a model type (either a specific
or an any model type).
10.2.2 Type System
Before we explain the type system for λ<> we define the typing environment as follows:
Definition 10.2.2 (Typing Environment). The typing environment is a partial function
Γ : X → T ypes, where the domain is the set of variable names and the co-domain the set
of types.
Syntactically, the typing environment will also be handled with set notations, e.g., x : τ ∈
Γ is equivalent to Γ(x) = τ . However, Definition 10.2.2 states that variable names in the
environment are always distinct.
We use the notation Γ, x : τ to extend environment Γ with a new binding x : τ . If a
binding of x exists in Γ, the new binding replaces the old one. We define the domain of a
typing relation as follows:
Definition 10.2.3. dom(Γ) ≡ {x | x : τ ∈ Γ}
We also define the subset relation between typing environments:
Definition 10.2.4. Γ ⊆ Γ′ ≡ ∀xτ.Γ(x) = τ implies Γ′ (x) = τ
The type system for λ<> is defined by a four-place model lifting relation
Γ ⊢L e
e′ : τ
where e is an expression in λ<> , e′ an expression in λ<>
L , τ the resulting type, and Γ
the typing environment. The model lifting relation is inductively defined using a set of
inference rules given in Figure 10.2 on page 1543 .
Definition 10.2.5 (Well typed expression in λ<> ). An expression e of language λ<> is
well typed (typable) in typing environment Γ if there exits e′ and τ , such that Γ ⊢L e
e′ : τ .
3 To make it easier to compare the different intermediate languages’ semantics, we list all the rules at the end
of the chapter.
142
10 Semantics of MKL
Language λ<> is a explicitly typed language and the model lifting can therefore be performed in a direct bottom up manner. Input to such a function would be an empty typing
environment and expression e1 and the output expression e2 whose type is τ .
We now give an overview of the translation rules for the model lifting relation. We first
consider the rules that are not lifting any expression, i.e., where the type of the expression
is not changed during translation.
The rules (L-VAR) for variables and (L-ABS) for lambda abstractions are standard
and similar to the simply-typed lambda calculus.
The rule (L-CONST) assumes a function ∆ : C → T ypes that applied to a constant
returns the constant’s type. We assume that the ∆ function cannot return a model type
and therefore give the following assumption:
Assumption A1 (∆-types).
If ∆(c) = τ then τ ∈ G or there exists τ1 and τ2 such that τ = τ1 → τ2 .
Now, consider the following examples:
(u : <Int → Int>) : <Int → Int>
(val 5 : Int) : <Int>
(10.2)
(10.3)
(u : <Int → Int>)@ (val 5 : Int) : <Int>
(λx : <>.x) (val 5 : Int) : <>
(10.4)
(10.5)
(λx : <Int>.x) (val 5 : Int) : <Int>
(u : <>)@ (val 5 : Int) : <>
(10.6)
(10.7)
ν(Int) : <Int>
(10.8)
(10.9)
In the first example, we see that an unknown tagged with a specific model type is of the
same type as the type tag (type rule (L-UK)). Also, the premise <> ∼ τ1 of (L-UK) makes
sure that unknowns are always tagged with only model types, i.e., unknown expressions
are always models.
Example (10.3) shows the use of type rule (L-VAL). The type of the embedded value
5 has type Int and the val expression has type <Int>. The intuition is that a model
value expressions embed arbitrary expression e with type τ with the result that val e : τ
is of type <τ >. We say that expression e is “lifted” to be of model type. The model value
is similar to values of type Dynamic developed by Abadi et. al. [1]. That work inspired
our design, but there are several differences, including the procedure for type checking.
In example (10.4), a model application applies an unknown to a model value. We
can see that the resulting model type is specific, and follows normal conventions of type
checking of applications, with the exception that all expressions are models. The example
demonstrates how the rule (L-MODAPP2) is used for deriving the type of the expression.
Note also that expression (10.4) is a value, i.e., the model application will never actually
be applied because there is no beta reduction for model applications.
So far all model types have been specific. However, in example (10.5), we see an ordinary function application, where the lambda binding variable of the lambda expression
is given any model type <>. Even though the argument has specific model type <Int>,
143
10.2 Type System and Model Lifting
the resulting type of the expression is <>. However, if the lambda’s binding variable has
a specific model type (example (10.6)), the specific type is preserved. In both cases, rule
Γ ⊢L e1
e′1 : τ11 → τ12 Γ ⊢L e2
e′2 : τ2
Γ ⊢L e1 e2
e′1 e′2 : τ12
τ11 ∼ τ2
(L-APP)
was used. Note how the type consistency premise τ11 ∼ τ2 is used instead of type equivalence between the type of the argument and the type of the abstraction’s formal parameter.
In the example (10.7), we see how rule (L-MODAPP1) is used when the type of the
left hand side’s expression is <>. Finally, in (10.8) we see how the ν(Int) constructor of
unknowns has a type Int and creates unknown expressions of model type <Int>. That
is, when unknowns are created, they must be of a specific model type, which conform to
the presence of premise <> ∼ τ1 of rule (L-UK).
The last three type rules are applicable for type checking a decon expression, i.e.,
the expression for deconstructing models.
The rule (L-DECON-UK) checks using premise <> ∼ τ1 that the type of e1 is a
model. Premise τ2 ∼ τ3 makes sure that the two alternative return expressions e2 and
e3 are consistent with each other. The last premise <> ∼ τ4 checks that the type of the
pattern tag type is a model. The restriction operator τ2 kτ3 is used to define the result type.
Note that the restriction operator itself is not symmetric, but because of premise τ2 ∼ τ3
we have directly from the definition of ∼ that τ2 kτ3 = τ3 kτ2 .
The rule (L-DECON-APP) is applicable when the deconstructor pattern is a model
application. Note that bindings for x1 and x2 are added to the typing environment when
deriving the type for e2 . Note also that the type that x1 and x2 are bound to is <> because
the deconstruction only knows that it was a model application that was deconstructed. We
know nothing about the specific types of the sub-expressions, just that they must be of
model type.
The last rule (L-DECON-VAL) is applicable when the deconstructor pattern is a
model value. The pattern’s tagged type τ4 is bound to x in the typing environment when
deriving the result for e2 . Note that τ4 is not checked for being a model type because the
embedded expression in a model value can be any type (typically not a model type).
10.2.3 Model Lifting
We saw in example (10.5) that a function can be applied to a value of type <Int>. The
function’s formal parameter can be of both the specific model type <Int> or of the any
model type <>. However, in the application case, if there is a mismatch between expressions of model type and expressions that are not models, there is an essential mechanism
for lifting non-models into models.
The purpose of this term translation is to lift expressions to model types when needed.
For example, consider an expression x + 3 where x is of a model type. During evaluation x can potentially be replaced by an unknown, which will make the computation
fail. The purpose is to lift such terms, so that the + operator and the second operand 3 are
lifted to become models. This is done by inserting val expressions. The actual model
lifting is performed by the five rules (L-APPM1) to (L-APPM2)
144
10 Semantics of MKL
The rule (L-APPM1) type checks an application expression. The rule is applicable
when τ2 is a model type and τ11 is not. This is checked by the two premises <τ11 > ∼ τ2
and τ11 6∼ τ2 . By encapsulating τ11 into a model type, the consistency check verifies
that τ2 is either <> or a specific model that is consistent with <τ11 >. The second premise
τ11 6∼ τ2 makes sure that the rule is exclusive with respect to rule (L-APP). If the premises
hold, the resulting expression e′1 is lifted using a val-expression. Note also that the
application is translated to a model application.
The rules (L-APPM2) and (L-APPM3) consider the application cases when e′1 is derived to be of type <>. The rule (L-APPM2) is applicable if τ2 is a model type (either
any model type or specific). In such a case, the application is transformed to a model
application. The rule (L-APPM3) is applicable if τ2 is not a model type. In such a case
e′2 is lifted to become a model. In both of these rules, the resulting type is <>.
The rules (L-APPM4) and (L-APPM5) are applicable when e′2 is derived to be of type
<τ11 → τ12 >. (L-APP4) is applicable if τ2 is a model type. If so, the resulting term is
transformed to a model application. Note also that the consistency checking makes sure
that the specific types are consistent, if τ2 was a specific model type. Rule (L-APPM5) is
applicable if τ11 ∼ τ2 and <τ11 > 6∼ τ2 . In such a case we lift e′2 .
10.3
Cast Insertion and Dynamic Semantics
For an interpreter or compiler implementation, the language λ<>
L is typically the language
that should be used for execution. In our prototype implementation (explained in Chapter 12) an extended version of this core language is used for evaluation. The big-step
semantics of λ<>
L for implementing such an interpreter is given in Appendix C. However, in this section we are interested in reasoning about properties of the language, and
in particular to prove type safety of the language. However, proving type safety directly
on λ<>
L is technically not feasible, since the consistency relation in e.g., the rule (L-APP)
makes it not possible to prove Preservation (see Chapter 10.4 for the Preservation lemma).
Instead, we define a cast insertion relation, which translates expressions in λ<>
L into a language called λ<>
.
In
the
latter
language,
the
type
consistency
relation
between
types are
LC
replaced with equality, making the proof possible.
<>
In contrast to λ<> and λ<>
L , which have the same syntax, λLC is updated as follows:
Intermediate Language λ<>
LC
Expressions
Values of models
Values with casts
Values
e
w
ξ
v
+=
::=
::=
::=
<>
e ∈ λ<>
LC ⊃ λL
hτ ⇐ τ ie
u : τ | v @ v | val v : τ
w | hτ ⇐ τ iξ
λx : τ.e | c | ξ
One new expression hτ2 ⇐ τ1 ie for casts is defined, where the expression e is cast from
source type τ1 to target type τ2 . The intuition is that expression e is of type τ1 and the
whole cast expression hτ2 ⇐ τ1 ie is of type τ2 .
We define new syntax for values of different categories. Let the meta-variable w
ranges over ModValues, i.e., values of model types. Moreover, we define a meta-variable
145
10.3 Cast Insertion and Dynamic Semantics
ξ that ranges over CastValues. This separation of values into different syntactic categories is necessary for making the language deterministic, i.e., that not more than one
rule of the runtime semantics is applicable at the same time.
10.3.1 Cast Insertion
Cast insertion is defined by a four-place cast insertion relation
Γ ⊢C e
e′ : τ
′
<>
where e is an expression in λ<>
L , e an expression in λLC , τ the resulting type, and Γ
the typing environment. The cast insertion relation is inductively defined using a set of
inference rules given in Figure 10.3 on page 154.
When there is a model lifting translation for an expression e, the expression e is welltyped with regards to a type system for λ<>
L . Because we do not make use of a specific
type system of λ<>
L , we omit its definition and instead state the soundness of translation
with regards to the cast insertion relation.
Lemma 10.1 (Model Lifting is Sound)
If Γ ⊢L e
e′ : τ then there exists an e′′ such that Γ ⊢C e′
Proof: By induction on a derivation of Γ ⊢L e
using the definition of type consistency.
e′′ : τ.
e′ : τ . All cases are straightforward
Let us now define the type system for λ<>
LC by a three-place typing relation
Γ ⊢ e:τ
where e is an expression in λ<>
LC , τ its type, and Γ the typing environment. The typing
relation is inductively defined in Figure 10.3 on page 155.
The aim of performing the cast insertion is to make it possible to prove type safety of
the language. There are three separate cases where we need to remove the consistency
relation to be able to prove the preservation lemma.
The first case is the existence of τ11 ∼ τ2 in rule (L-APP). Trying to prove preservation of λ<> by induction on a derivation of Γ ⊢L e
e′ : τ will fail on the (L-APP) case.
Hence, the trick in the cast insertion is shown in the conclusion of rule:
Γ ⊢C e1
e′1 : τ11 → τ12 Γ ⊢C e2
e′2 : τ2 τ11 ∼ τ2
Γ ⊢C e1 e2
e′1 (hτ11 ⇐ τ2 ie′2 ) : τ12
(C-APP)
By casting e′2 from τ2 to τ11 , the expression hτ11 ⇐ τ2 ie′2 has type τ11 , eliminating the
need for the premise τ11 ∼ τ2 .
The second case where casts are needed is for the rules (L-DECON-UK), (L-DECONAPP), and (L-DECON-VAL). All these three rules are treated in the same way in this case.
Therefore we will concentrate on the (L-DECON-UK) rule. The objective is to remove
the premise τ2 ∼ τ3 and instead have τ2 = τ3 . Consider rule (T-DECON-UK) were
both e2 and e3 derive the same type τ2 . Because τ2 ∼ τ3 in (L-DECON-UK), we can in
(C-DECON-UK) cast both τ2 and τ3 to τ5 because τ5 = τ2 kτ3 .
146
10 Semantics of MKL
The third case involving casts is the result of the problem that model applications
can be of both specific model types <τ > and <> for some τ . If both model types exist,
we cannot prove progress for the (T-DECON-APP) case, because we cannot derive the
specific types for the sub-values of e1 in (T-DECON-APP). The solution we use is to
assume that the types of the sub-expressions of a model application are always <>. In
such a case, we must have an inversion lemma, stating that the sub-expressions are of
type <>. Note that we therefore have only one rule for model application in λ<>
LC : (TMODAPP). One problem with proving soundness of cast insertion is that the type τ must
be the same. Note that the resulting type of (C-MODAPP2) is <τ12 > and not <>. The
trick in (C-MODAPP2) is that we first cast each sub-expression of the model application
to <>, and then cast the whole model application to <τ12 >.
Finally, we prove the soundness of cast insertion:
Lemma 10.2 (Cast Insertion is Sound)
If Γ ⊢C e
e′ : τ then Γ ⊢ e′ : τ .
Proof: By induction on a derivation of Γ ⊢C e
e′ : τ . The proof is straightforward,
where the case (C-MODAPP2) uses Proposition 10.1 (g).
10.3.2 Dynamic Semantics
We define the dynamic semantics of λ<>
LC using operational semantics with small-step
style, pioneered by Plotkin [126]. The shape of the single-step relation is
e | U −→ e′ | U ′
where expression e is reduced to e′ in one step, and U and U ′ are starting and ending
states for the store of unknowns. The meta-variable U ⊆ U ranges over a (potentially
empty) set of unknowns. Hence, the operational semantics includes computational effects
in terms of new unknowns that are created during evaluation. However, the unknowns
cannot be assigned values and could be considered as symbols that can only be compared
using equality.
Consider now the small-step semantics, defined as a set of inference rules in Figure 10.5 on page 157. The first eight rules of relation e | U −→ e′ | U ′ are computation
rules that reduce an expression one step. The next seven rules are congruence rules which
determine the used evaluation strategy; in this case call-by-value.
Application
The rule (E-APPABS) is the standard application rule (β-reduction). The value v1 is
substituted for x in e1 . The notation [x 7→ v1 ]e1 stands for standard capture-avoiding
substitution, where v1 is substituted for all x that appear free in e1 . For completeness the
definitions of substitution and the free variable function F V (e) are given in Figure 10.6
on page 158.
This leads us to the following convention:
Convention 2. All expressions that differ only with respect to names of binding variables
are exchangeable in all contexts.
10.3 Cast Insertion and Dynamic Semantics
147
Hence, for example, expressions λx :τ.x and λy :τ.y are exchangeable in all contexts. Our
language only evaluates closed expressions meaning that the substituted expression will
never contain free variables and therefore renaming is not needed to avoid capturing.
The second rule for application is (E-DELTA) where e1 is evaluated to a constant c
instead of a lambda. We use the standard notation of a δ function for abstracting the
computation of built-in operators, i.e., δ(c, v) returns the result of applying c to v.
The two congruence rules (E-APP1) and (E-APP2) are used for evaluating application
expressions. For an expression e1 e2 , the rule (E-APP1) is first used for evaluating e1 to a
value. Then, the rule (E-APP2) evaluates e2 to a value. Finally, either rule (E-APPABS)
or (E-DELTA) apply.
Unknowns, Model Applications, and Model Values
There are three kinds of model expressions: unknowns u : τ , model values val v : τ , and
model application values v1 @ v1 .
The computation rule (E-NEWUK) creates new unknowns when evaluated. The
premise u ∈
/ U means that we pick a fresh unknown u that is not in the set U . The
returned state is augmented with the new unknown. Note that the resulting unknown
expression u : <τ1 > is “tagged” with the type <τ1 > from the ν-expression.
Using the unknown binder for creating new unknowns intentionally introduces the
side effect that two expressions containing let unknown binders do not evaluated to the
same value. This effect is by design, for example recall the Circuit model, where two
Resistor components are created. The Resistor model is a function that contains
let unknown binders for e.g., the current through the component. These unknowns must
be distinct, which is performed by the effect in the rule (E-NEWUK).
Unknowns can be supplied as arguments to functions. However, because unknowns
are symbols that cannot be bound to a value, there is no application rule e1 e2 that evaluates e1 to unknown u and then performs the application. Instead a model application
expression e1 @ e2 is used to create a data structure. A model application expression can
from a untyped point of view be seen as a tuple holding two expressions, which are by
rules (E-MODAPP1) and (E-MODAPP2) evaluated to a value.
The last kind of model expression is model values, written val e1 : τ . A model value
embeds an expression e1 and stores the type τ of e1 . Its evaluation rule (E-MODVAL)
evaluates e1 until it becomes a value.
Deconstructing Models
The previous subsection describes how model expressions are created and evaluated to
values. The last two computation rules (E-DECON-T) and (E-DECON-F) are used for
deconstructing models, i.e., unknowns u : τ , model values val v : τ , or model application
values v1 @ v1 .
Consider now the expression
(u : <Int → Int>)@ (val 5 : Int)
(10.10)
which has been evaluated to a value. Because u is an unknown of function type, the
expression cannot be evaluated further. However, it can be deconstructed using the expression decon(v, d, e2 , e3 ), which can be read as “match value v with pattern d. If it
148
10 Semantics of MKL
matches, evaluate and return e2 after substitution of values for pattern variables in d. If it
does not match, evaluate and return the value for e3 ”.
Now, consider the congruence rule (E-DECON) in Figure 10.5. The rule evaluates
the first expression e1 . When e1 is a value, either reduction rule (E-DECON-T) or (EDECON-F) apply. The value v1 , the deconstructor pattern d, and the expression e2 are in
both rules given to the match relation. If the match is true, the rule (E-DECON-T) applies
and e′2 is returned. If the match is false, the rule (E-DECON-F) applies and e3 is returned.
Note that the axioms (M-UK), (M-MAPP), and (M-MVAL) of the match relation checks
the shape of the expression (that it is an unknown, model application, or a model value).
Moreover, for (M-UK) and (M-MVAL) it is also checked that the type tag τ1 is equal to
the type tag of the pattern.
Let eexample denote the example expression given in (10.10). The following examples
show the basic idea of the model deconstructor.
decon(eexample , x @ y, x, val 1.1 : Real) | U −→ u : <Int → Int> | U
decon(eexample , uk : Real, x, val 1.1 : Real) | U −→ val 1.1 : Real | U
decon(eexample , x @ y, y, val 1.1 : Real) | U −→ val 5 : Int | U
decon(val 5 : Int, val x : Int, x, 20) | U −→ 5 | U
decon(u : <Int → Int>, uk : <Int → Int>, 1, 2) | U −→ 1 | U
decon(u : <Int → Int>, uk : <Real>, 1, 2) | U −→ 2 | U
10.3.3 Casts
The previous rules describe the fundamental semantics of λ<>
LC . There are also three
computation rules (E-CAST-ARROW), (E-CAST-GAMMA), and (E-CAST-MODEL), as
well as one congruence rule (E-CAST) that handle casts. The casts semantics shall not be
seen as a property of the language, but only an approach for enabling a type safety proof.
The rationale for this statement is that a cast expression is first evaluated to an expression
hτ2 ⇐ τ1 iv using (E-CAST), and then handled by the following rules:
• (E-CAST-ARROW) - the case is broken up into two separate casts, by introducing
a new lambda abstraction.
• (E-CAST-GAMMA) - the cast is thrown away.
• (E-CAST-MODEL) - casts surrounding a model value gets thrown away before
deconstructing a model.
Note that the resulting value can include casts, which is also defined as a value.
10.4
Type Safety
In this section we prove type safety by first proving the usual progress and preserva<>
tion lemmas for the intermediate language λ<>
is then estabLC . Type safety for λ
lished using the soundness of model lifting (Lemma 10.1) and soundness of cast insertion
10.4 Type Safety
149
(Lemma 10.2). The proof strategy for type safety that we use has its origins in the syntactic soundness approach by Wright and Felleisen [151], but is now typically organized
in a different way. We are using an approach similar to Pierce [124].
We start by proving basic lemmas about the typing relation. First, we prove the inversion of typing relation.
Lemma 10.3 (Inversion of Typing Relation)
1. If Γ ⊢ x : τ then Γ(x) = τ .
2. If Γ ⊢ (u : τ1 ) : τ then τ = τ1 and <> ∼ τ1 .
3. If Γ ⊢ λx : τ1 .e2 : τ then there exists a τ2 such that τ = τ1 → τ2 and
Γ, x : τ1 ⊢ e2 : τ2 .
4. If Γ ⊢ c : τ then ∆(c) = τ .
5. If Γ ⊢ ν(τ1 ) : τ then τ = <τ1 >.
6. If Γ ⊢ (val e1 : τ1 ) : τ then τ = <τ1 > and Γ ⊢ e1 : τ1 .
7. If Γ ⊢ e1 e2 : τ then there exists a τ11 such that Γ ⊢ e1 : τ11 → τ and Γ ⊢ e2 : τ11 .
8. If Γ ⊢ e1 @ e2 : τ then τ = <> and Γ ⊢ e1 : <> and Γ ⊢ e2 : <>.
9. If Γ ⊢ hτ2 ⇐ τ1 ie1 : τ then τ = τ2 and Γ ⊢ e1 : τ1 and τ1 ∼ τ2 .
10. If Γ ⊢ decon(e1 , uk : τ4 , e2 , e3 ) : τ then there exists a τ1 such that
Γ ⊢ e1 : τ1 and Γ ⊢ e2 : τ and Γ ⊢ e3 : τ and <> ∼ τ1 and <> ∼ τ4 .
11. If Γ ⊢ decon(e1 , x1 @ x2 , e2 , e3 ) : τ then there exists a τ1 such that
Γ ⊢ e1 : τ1 and Γ, x1 : <>, x2 : <> ⊢ e2 : τ and Γ ⊢ e3 : τ and <> ∼ τ1 .
12. If Γ ⊢ decon(e1 , val x : τ4 , e2 , e3 ) : τ then there exists a τ1 such that
Γ ⊢ e1 : τ1 and Γ, x : τ4 ⊢ e2 : τ and Γ ⊢ e3 : τ and <> ∼ τ1 .
Proof: Immediate from the definition of Γ ⊢ e′ : τ .
The next lemmas tell us the shape of a value, given its type:
Lemma 10.4 (Canonical Forms)
1. If Γ ⊢ v : γ then ∃c ∈ C. c = v.
2. If Γ ⊢ v : τ1 → τ2 then (∃x e. (λx : τ1 .e) = v) or (∃c.c = v).
3. If Γ ⊢ v : τ and <> ∼ τ then (∃u. u : τ = v) or (∃τ1 v1 . τ = <τ1 >∧
val v1 : τ1 = v) or (∃v1 v2 . τ = <> ∧ v1 @ v2 = v) or ∃τ1 ξ.hτ ⇐ τ1 iξ = v.
Proof:
1. By induction on a derivation of the statement Γ ⊢ v : γ.
2. By induction on a derivation of the statement Γ ⊢ v : τ1 → τ2 .
3. By induction on a derivation of the statement Γ ⊢ v : τ . Case (T-CONST)
uses Assumption A1.
We are now ready to state one of the main lemmas of the proof, that a well-typed expression is either a value or we can take a step:
Lemma 10.5 (Progress)
If ⊢ e : τ then e ∈ Values or for all U there exists U ′ and e′ such that e | U −→ e′ | U ′ .
150
10 Semantics of MKL
Proof: By induction on a derivation of ⊢ e : τ . Case (T-VAR) cannot occur, since e is
closed. In cases (T-UK), (T-ABS), and (T-CONST) e ∈ Values. Case (T-APP) uses the
Canonical Form Lemma number 2. Cases (T-VAL) and (T-MODAPP) are straightforward.
Case (T-CAST): By induction hypothesis, e1 can either take a step or it is a value.
If it can take a step, rule (E-CAST) apply. If it is a value, we perform case analysis
on values. If e1 ∈ CastValues, then e is a value. If e1 is a lambda, Inversion Lemma
number 3 is used and (E-CAST-ARROW) apply. If e1 is s constant, Inversion Lemma
number 4 together with Assumption A1 gives two subcases where (E-CAST-ARROW)
and (E-CAST-GAMMA) applies respectively.
Cases (T-DECON-UK), (T-DECON-APP), and (T-DECON-VAL) are proven in the
same manner. By induction hypothesis e1 can either take a step or is a value. If it can
take a step, (E-DECON) applies. In case of a value, the Canonical Form Lemma number
3 gives four cases. If e1 ∈ CastValues (E-CAST-MODEL) applies. In the other cases
(E-DECON-T) or (E-DECON-F) apply.
Assumption A2 (δ-typability).
If ∆(c) = τ1 → τ2 and Γ ⊢ v : τ1 then Γ ⊢ δ(c, v) : τ2 .
Towards proving the Preservation Lemma, we need for the case (T-APP) a Substitution
Lemma that in turn needs an Environment Weakening Lemma.
Lemma 10.6 (Environment Weakening)
If Γ ⊢ e : τ and Γ ⊆ Γ′ then Γ′ ⊢ e : τ .
Proof: Straightforward induction on a derivation of Γ ⊢ e : τ .
Lemma 10.7 (Substitution)
If Γ, y : τ ′ ⊢ e : τ and Γ ⊢ e′ : τ ′ then Γ ⊢ [y 7→ e′ ]e : τ .
Proof: Straightforward induction on a derivation of Γ ⊢ e : τ , where case (T-ABS) uses
the Environment Weakening Lemma.
Lemma 10.8 (Preservation)
If Γ ⊢ e : τ and e | U −→ e′ | U ′ then Γ ⊢ e′ : τ .
Proof: By induction on a derivation of Γ ⊢ e : τ . Cases (T-VAR), (T-UK), (T-ABS),
and (T-CONST) are vacuously true. Case (T-NEWUK) is straightforward. Case (TAPP) uses the inversion lemma, substitution lemma, and Assumption A2. Case (TCAST) has three cases, where case (E-CAST-ARROW) uses the Environment Weakening
Lemma. Cases (T-DECON-UK), (T-DECON-APP), and (T-DECON-VAL) use the Inversion Lemma.
Theorem 10.1 (Type Safety of λ<> )
If ⊢L e1
e2 : τ then there exists an e3 such that ⊢C e2
e3 : τ and (if e3 | U3 −→∗
e4 | U4 then ⊢ e4 : τ and (e4 ∈ Values or there exists e5 and U5 such that e4 | U4 −→
e5 | U5 )).
151
10.5 Extending the Core
Proof: By applying Lemma 10.1, soundness of model lifting, to ⊢L e1
e2 : τ we have
⊢C e2
e3 : τ for some e3 . Also, by soundness of cast insertion (Lemma 10.2), we have
⊢ e3 : τ . By induction on a derivation of e | U −→∗ e′ | U ′ we have two cases: In the base
case (RTC-REFL) e = e′ and we directly have ⊢ e′ : τ . By applying Progress to ⊢ e′ : τ
we show that e′ is a value or there exists e′′ and U ′′ such that e′ | U ′ −→ e′′ | U ′′ . For case
(RTC-STEP) we have by induction hypothesis ⊢ e′ : τ . Also, by applying Preservation to
assumption e′ | U ′ −→ e′′ | U ′′ , we obtain ⊢ e′′ : τ . By applying Progress to ⊢ e′′ : τ we
reach the conclusion.
10.5 Extending the Core
In this section, we discuss some essential parts when extending the core of MKL with
other constructs.
10.5.1 Other Expressions and the Bot Type
We do not see that other expressions, such as if-expressions, the list constructor, tuples,
and built-in ADTs for Map and Set, give any extra concern regarding the extra complexity
of model types. No other expressions are lifted to models than the expressions explained
in the previous section.
One detail that can be elegantly handled using type consistency is the type for the
error expression, i.e., an expression that should terminate the program. We give an
error the type Bot. The problem is however how to type this when the type system
does not have subtyping. One solution is to use the consistency relation. If we extend the
restriction operator τ1 kτ2 with a rule for Bot we get the following extended definition:
τ kτ
Restriction (extended)
<τ1 > k<τ2 >
τ11 → τ12 kτ21 →τ22
τ1 kτ2
=
=
=
=
<>
<τ1 kτ2 >
τ11 kτ21 → τ12 kτ22
τ1
Bot kτ
=
τ
<τ > k<>
if τ1 6= <τ3 > and τ1 6= τ11 → τ12
and τ1 6= Bot
for some τ3 , τ11 , and τ12
Lemma 10.9 (Consistency of Bot)
∀τ.(Bot ∼ τ and τ ∼ Bot)
Proof: By rule 5 of the definition of restriction (extended) we have Bot kτ = τ and by
rule 4 we have τ kBot = τ . Hence, Bot ∼ τ by using Definition 10.2.1. Because ∼ is
symmetric, we have τ ∼ Bot.
Hence, all types are consistent with Bot. It turns out that this approach also solves the
problem of specifying types explicitly for the empty list in a language without type vari-
152
10 Semantics of MKL
ables. We simply give the empty list type [Bot]. Type Bot cannot be defined explicitly
by the user because this would break the type system.
10.5.2 Pattern Matching
We have in previous chapters showed that pattern matching is an essential part of the
language. However, pattern matching using match-expressions are not part of the core
language presented in this chapter. Instead match-expressions are defined using derived
forms, meaning that there is a translation step between the concrete syntactic form of a
match-expression and an expression in an intermediate language based on the semantics
presented in this chapter. This translation has not yet been formally defined for MKL.
10.5.3 Lifting and Binary Operators
One problem of symmetry appears when lifting binary operators that can be partially
applied, e.g., (+) of type Int -> Int -> Int. For example, in expression
let x:<Int> in
((+) x) 3
sub-expression (+) x is lifted to a model application because x is of model type. Hence,
((+) @ x) applied to 3 is also lifted. However, if the order of operands to (+) is
reversed
let x:<Int> in
((+) 3) x
expression (+) 3 will not be lifted because the argument 3 is not of model type. Because operator (+) is in curried form, (+) can be partially applied to 3. Hence, the
value of (+) 3 is embedded into a model value instead of being translated into a model
application.
Our first attempt to solve this problem of non-symmetry was to include special rules
for binary built-in operators in the model lifting relation, i.e., as part of the type system.
However, this resulted in a very complicated type system. Informally, our solution in the
implementation is instead to add an extra match rule for decon where model values with
embedded partially applied binary operators can be deconstructed.
10.5.4 Equality
In the full MKL language, we have a built-in polymorphic equality operator. In the current
version of the language, we define equivalence of values with binary relation ≡α , meaning
syntactic equality up to renaming of bound variables (α-conversion). This is satisfying for
constant terms, tuples, unknowns etc. in an interpreted setting. The approach works for
lambda expressions, but the current prototype implementation gets very slow because the
environments of the closures are compared. Alpha-equivalence is handled by nameless
representation of the environment, i.e., we use de Bruijn-indices [46].
Type and translation rules for equality can be defined as follows:
153
10.6 Chapter Summary and Conclusions
Γ ⊢L e1
e′1 : τ1 Γ ⊢L e2
Γ ⊢L e1 == e2
e′2 : τ2 <> 6∼ τ1 <> ∼ τ2 <τ1 > ∼ τ2
(val e′1 : τ1 == e′2 ) : Bool
(L-EQUAL1)
Γ ⊢L e1
e′1 : τ1 Γ ⊢L e2
Γ ⊢L e1 == e2
e′2 : τ2 <> ∼ τ1 <> 6∼ τ2 τ1 ∼ <τ2 >
(e′1 == val e′2 : τ2 ) : Bool
(L-EQUAL2)
Γ ⊢L e1
e′1 : τ1
Γ ⊢L e2
e′2 : τ2
τ1 ∼ τ2
′
′
Γ ⊢L e1 == e2
e1 == e2 : Bool
(L-EQUAL3)
Hence, if one of the operands is of model type and the other one is not, the expression
that is not a model is lifted (rules (L-EQUAL1) and (L-EQUAL2)). If both operands are
models or none of them, no lifting occurs (L-EQUAL3).
Note that in contrast to an application expression, the equality operator is never lifted
to become a model. If that would be the case, it could not be used to compare e.g.,
unknowns. An alternative would be to have more than one equality operator, one that
is lifted and one that is not. However, at the current stage, we do not see any reason to
introduce this.
10.6 Chapter Summary and Conclusions
We have in this chapter presented a formal semantics of an essential core of the MKL
language. We have tried to formulate our semantics with rigor by making all definitions
as clear as possible.
The choice of small-step semantics, to have several intermediate languages, and to
insert casts are all choices due to the type safety proof. Our type safety proof increases
our confidence of the language, but we would at the same time stress that it does not
guarantee correctness between the formal semantics and an implementation.
154
10 Semantics of MKL
Γ ⊢L e
Γ(x) = τ1
Γ ⊢L x
x : τ1
<> ∼ τ1
Γ ⊢L u : τ 1
(u : τ1 ) : τ1
(L-VAR)
Γ, x : τ1 ⊢L e2
e′2 : τ2
Γ ⊢L λx : τ1 .e2
λx : τ1 .e′2 : τ1 → τ2
Γ ⊢L ν(τ1 )
ν(τ1 ) : <τ1 >
e′1 : τ11 → τ12 Γ ⊢L e2
e′2 : τ2
′ ′
Γ ⊢L e 1 e 2
e1 e2 : τ12
(L-VAL)
τ11 ∼ τ2
e′1 : τ11 → τ12 Γ ⊢L e2
e′2 : τ2 <τ11 > ∼ τ2
′
Γ ⊢L e 1 e 2
(val e1 : τ11 → τ12 )@ e′2 : <τ12 >
Γ ⊢L e 1
Γ ⊢L e 1
e′1 : <> Γ ⊢L e2
e′2 : τ2
′
′
Γ ⊢L e 1 e 2
e1 @ e2 : <>
<> ∼ τ2
Γ ⊢L e 1
e′1 : <> Γ ⊢L e2
e′2 : τ2 <> 6∼ τ2
Γ ⊢L e 1 e 2
e′1 @ (val e′2 : τ2 ) : <>
Γ ⊢L e 1
Γ ⊢L e 1
e′1 : <τ11 → τ12 > Γ ⊢L e2
e′2 : τ2
′
′
Γ ⊢L e 1 e 2
e1 @ e2 : <τ12 >
Γ ⊢L e 1
e′1 : <> Γ ⊢L e2
e′2 : τ2
′
Γ ⊢L e 1 @ e 2
e1 @ e′2 : <>
<> ∼ τ2
e′1 : <τ11 → τ12 > Γ ⊢L e2
e′2 : τ2
Γ ⊢L e 1 @ e 2
e′1 @ e′2 : <τ12 >
(L-APP)
τ11 6∼ τ2
(L-APPM1)
(L-APPM2)
(L-APPM3)
<τ11 > ∼ τ2
e′1 : <τ11 → τ12 > Γ ⊢L e2
e′2 : τ2 τ11 ∼ τ2
′
Γ ⊢L e 1 e 2
e1 @ (val e′2 : τ2 ) : <τ12 >
Γ ⊢L e 1
(L-CONST)
(L-NEWUK)
Γ ⊢L e 1
e′1 : τ1
Γ ⊢L val e1 : τ1
(val e′1 : τ1 ) : <τ1 >
Γ ⊢L e 1
(L-UK)
∆(c) = τ1
Γ ⊢L c
c : τ1
(L-ABS)
e′ : τ
(L-APPM4)
<τ11 > 6∼ τ2
(L-APPM5)
(L-MODAPP1)
<τ11 > ∼ τ2
(L-MODAPP2)
e′1 : τ1 Γ ⊢L e2
e′2 : τ2 Γ ⊢L e3
e′3 : τ3
<> ∼ τ1
τ2 ∼ τ3
<> ∼ τ4
Γ ⊢L decon(e1 , uk : τ4 , e2 , e3 )
decon(e′1 , uk : τ4 , e′2 , e′3 ) : (τ2 kτ3 )
Γ ⊢L e 1
(L-DECON-UK)
Γ ⊢L e 1
e′1 : τ1
Γ, x1 : <>, x2 : <> ⊢L e2
e′2 : τ2
′
Γ ⊢L e 3
e3 : τ3
<> ∼ τ1
τ2 ∼ τ3
Γ ⊢L decon(e1 , x1 @ x2 , e2 , e3 )
decon(e′1 , x1 @ x2 , e′2 , e′3 ) : (τ2 kτ3 )
Γ ⊢L e 1
e′1 : τ1
Γ ⊢L e 3
e′3 : τ3
Γ ⊢L decon(e1 , val x : τ4 , e2 , e3 )
Γ, x : τ4 ⊢L e2
e′2 : τ2
<> ∼ τ1
τ2 ∼ τ3
decon(e′1 , val x : τ4 , e′2 , e′3 ) : (τ2 kτ3 )
Figure 10.2: Model lifting
(L-DECON-APP)
(L-DECON-VAL)
155
10.6 Chapter Summary and Conclusions
Γ ⊢C e
Γ(x) = τ1
Γ ⊢C x
x : τ1
<> ∼ τ1
Γ ⊢C (u : τ1 )
(u : τ1 ) : τ1
(C-VAR)
Γ, x : τ1 ⊢C e2
e′2 : τ2
Γ ⊢C λx : τ1 .e2
λx : τ1 .e′2 : τ1 → τ2
Γ ⊢C ν(τ1 )
(C-ABS)
ν(τ1 ) : <τ1 >
(C-UK)
∆(c) = τ1
Γ ⊢C c
c : τ1
(C-VAL)
e′1 : τ11 → τ12 Γ ⊢C e2
e′2 : τ2 τ11 ∼ τ2
′
Γ ⊢C e 1 e 2
e1 (hτ11 ⇐ τ2 ie′2 ) : τ12
Γ ⊢C e 1
e′1 : <> Γ ⊢C e2
e′2 : τ2 <> ∼ τ2
′
Γ ⊢C e 1 @ e 2
e1 @ h<> ⇐ τ2 ie′2 : <>
h<τ12 > ⇐ <>i(e′′1 @ e′′2 ) : <τ12 >
Γ ⊢C e 1
e′1 : τ1 Γ ⊢C e2
e′2 : τ2 Γ ⊢C e3
e′3 : τ3
<> ∼ τ1
τ2 ∼ τ3
<> ∼ τ4
τ5 = τ2 kτ3
e′′2 = hτ5 ⇐ τ2 ie′2
e′′3 = hτ5 ⇐ τ3 ie′3
Γ ⊢C decon(e1 , uk : τ4 , e2 , e3 )
(C-APP)
(C-MODAPP1)
Γ ⊢C e 1
e′1 : <τ11 → τ12 > Γ ⊢C e2
e′2 : τ2 <τ11 > ∼ τ2
′′
′
′′
e1 = (h<> ⇐ <τ11 → τ12 >ie1 )
e2 = h<> ⇐ τ2 ie′2
Γ ⊢C e 1 @ e 2
decon(e′1 , uk : τ4 , e′′2 , e′′3 ) : τ5
(C-MODAPP2)
(C-DECON-UK)
Γ ⊢C e 1
e′1 : τ1
Γ, x1 : <>, x2 : <> ⊢C e2
e′2 : τ2
Γ ⊢C e 3
e′3 : τ3
<> ∼ τ1
τ2 ∼ τ3
τ4 = τ2 kτ3
e′′2 = hτ4 ⇐ τ2 ie′2
e′′3 = hτ4 ⇐ τ3 ie′3
Γ ⊢C decon(e1 , x1 @ x2 , e2 , e3 )
decon(e′1 , x1 @ x2 , e′′2 , e′′3 ) : τ4
Γ ⊢C e 1
e′1 : τ1
Γ, x : τ4 ⊢C e2
e′2 : τ2
Γ ⊢C e 3
e′3 : τ3
<> ∼ τ1
τ2 ∼ τ3
τ5 = τ2 kτ3
e′′2 = hτ5 ⇐ τ2 ie′2
e′′3 = hτ5 ⇐ τ3 ie′3
Γ ⊢C decon(e1 , val x : τ4 , e2 , e3 )
(C-CONST)
(C-NEWUK)
Γ ⊢C e 1
e′1 : τ1
Γ ⊢C val e1 : τ1
(val e′1 : τ1 ) : <τ1 >
Γ ⊢C e 1
e′ : τ
decon(e′1 , val x : τ4 , e′′2 , e′′3 ) : τ5
Figure 10.3: Cast insertion
(C-DECON-APP)
(C-DECON-VAL)
156
10 Semantics of MKL
Γ ⊢ e:τ
Γ(x) = τ1
Γ ⊢ x : τ1
(T-VAR)
Γ, x : τ1 ⊢ e2 : τ2
Γ ⊢ λx : τ1 .e2 : τ1 → τ2
Γ ⊢ ν(τ1 ) : <τ1 >
<> ∼ τ1
Γ ⊢ (u : τ1 ) : τ1
(T-ABS)
(T-NEWUK)
∆(c) = τ1
Γ ⊢ c : τ1
Γ ⊢ e1 : <>
Γ ⊢ e2 : <>
Γ ⊢ e1 @ e2 : <>
Γ ⊢ e1 : τ1
τ1 ∼ τ2
Γ ⊢ hτ2 ⇐ τ1 ie1 : τ2
Γ ⊢ e1 : τ1
Γ ⊢ e1 : τ1
(T-CONST)
Γ ⊢ e1 : τ1
Γ ⊢ (val e1 : τ1 ) : <τ1 >
Γ ⊢ e1 : τ11 → τ12 Γ ⊢ e2 : τ11
Γ ⊢ e1 e2 : τ12
Γ ⊢ e1 : τ1
(T-UK)
(T-VAL)
(T-APP)
(T-MODAPP)
(T-CAST)
Γ ⊢ e2 : τ2
Γ ⊢ e3 : τ2
<> ∼ τ1
Γ ⊢ decon(e1 , uk : τ4 , e2 , e3 ) : τ2
<> ∼ τ4
Γ, x1 : <>, x2 : <> ⊢ e2 : τ2
Γ ⊢ e3 : τ2
Γ ⊢ decon(e1 , x1 @ x2 , e2 , e3 ) : τ2
<> ∼ τ1
Γ, x : τ4 ⊢ e2 : τ2
Γ ⊢ e3 : τ2
Γ ⊢ decon(e1 , val x : τ4 , e2 , e3 ) : τ2
<> ∼ τ1
Figure 10.4: Type System for λ<>
LC
(T-DECON-UK)
(T-DECON-APP)
(T-DECON-VAL)
157
10.6 Chapter Summary and Conclusions
e | U −→ e′ | U ′
Computation Rules
(λx : τ1 .e1 )v1 | U −→ [x 7→ v1 ]e1 | U (E-APPABS)
c1 v1 | U −→ δ(c1 , v1 ) | U (E-DELTA)
u∈
/U
(E-NEWUK)
ν(τ1 ) | U −→ u : <τ1 > | U ∪ {u}
match(w1 , d, e2 , e′2 )
decon(w1 , d, e2 , e3 ) | U −→ e′2 | U
(E-DECON-T)
¬match(w1 , d, e2 , e′2 )
decon(w1 , d, e2 , e3 ) | U −→ e3 | U
(E-DECON-F)
hτ1 → τ2 ⇐ τ3 → τ4 iv1 | U −→ λx : τ1 .hτ2 ⇐ τ4 i(v1 hτ3 ⇐ τ1 ix) | U (E-CAST-ARROW)
hγ ⇐ γiv1 | U −→ v1 | U (E-CAST-GAMMA)
decon(hτ2 ⇐ τ1 iξ1 , d, e1 , e2 ) | U −→ decon(ξ1 , d, e1 , e2 ) | U (E-CAST-MODEL)
e | U −→ e′ | U ′
Congruence Rules
e1 | U −→ e′1 | U ′
e1 e2 | U −→ e′1 e2 | U ′
e1 | U −→ e′1 | U ′
e1 @ e2 | U −→
e′1 @ e2
|U
′
(E-APP1)
(E-MODAPP1)
e2 | U −→ e′2 | U ′
v1 e2 | U −→ v1 e′2 | U ′
(E-APP2)
e2 | U −→ e′2 | U ′
v1 @ e2 | U −→ v1 @ e′2 | U ′
e1 | U −→ e′1 | U ′
val e1 : τ1 | U −→ val e′1 : τ1 | U ′
(E-MODAPP2)
(E-MODVAL)
e1 | U −→ e′1 | U ′
decon(e1 , d, e2 , e3 ) | U −→ decon(e′1 , d, e2 , e3 ) | U ′
e1 | U −→ e′1 | U ′
hτ2 ⇐ τ1 ie1 | U −→ hτ2 ⇐ τ1 ie′1 | U ′
(E-DECON)
(E-CAST)
match(e1 , d, e2 , e3 )
Match Rules
match(u : τ1 , uk : τ1 , e1 , e1 ) (M-UK)
match(v1 @ v2 , x1 @ x2 , e1 , (λx1 : <>.λx2 : <>.e1 ) v1 v2 ) (M-MAPP)
match(val v1 : τ1 , val x : τ1 , e1 , (λx : τ1 .e1 ) v1 ) (M-MVAL)
Reflexive Transitive Closure
e| U −→∗ e′ | U ′ (RTC-REFL)
e | U −→∗ e′ | U ′
e | U −→∗ e′ | U ′ e′ | U ′ −→ e′′ | U ′′
e | U −→∗ e′′ | U ′′
Figure 10.5: Small-step operational semantics for λ<>
LC .
(RTC-STEP)
158
10 Semantics of MKL
Free variables
F V(x)
F V(λx :τ.e)
F V(e1 e2 )
F V(c)
F V(u : τ )
F V(ν(τ ))
F V(e1 @ e2 )
F V(val e : τ )
F V(decon(e1 , d, e2 , e3 ))
Substitiution
[x 7→ e]x
[x 7→ e]y
[x 7→ e]λy : τ.e1
[x 7→ e]e1 e2
[x 7→ e]c
[x 7→ e]u : τ
[x 7→ e]ν(τ )
[x 7→ e]e1 @ e2
[x 7→ e]val e1 : τ
[x 7→ e]decon(e1 , d, e2 , e3 )
F V(e)
{x}
F V(e) \ {x}
F V(e1 ) ∪ F V(e2 )
∅
∅
∅
F V(e1 ) ∪ F V(e2 )
F V(e)
F V(e1 ) ∪ F V(e2 ) ∪ F V(e3 )
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
[x 7→ e]e
e
y
if x 6= y
λy :τ.[x 7→ e]e1
if x 6= y and y ∈
/ F V(e)
[x 7→ e]e1 [x 7→ e]e2
c
u:τ
ν(τ )
[x 7→ e]e1 @ [x 7→ e]e2
val [x 7→ e]e1 : τ
decon([x 7→ e]e1 , d, [x 7→ e]e2 , [x 7→ e]e3 )
Figure 10.6: Free variables and substitution.
11
Elaboration Semantics
Chapter 2, we defined the elaboration phase as the translation from a model to a
hybrid DAE. In this chapter, we discuss the elaboration phase with focus on two main
areas: connection semantics and extracting model information. This chapter is organized
as follows:
I
N
• We give an overview of the different activities that are typically involved during
elaboration in an compiler for an EOO language. We explain briefly when type
checking is performed on MKL models and how the instance hierarchy of the model
is collapsed (Section 11.1).
• We explain the connection semantics for handling acausal connections in MKL, as
well as discuss how the semantics relate to Modelica’s informal connection semantics. The semantics are formally defined using a recursive functional definition.
This is followed by an executable specification where the semantics are also specified as MKL functions (Section 11.2).
• We discuss the problem of extracting simulation results from a model, i.e., how to
specify which variables should be presented to a user. We suggest a solution to
the problem using the construct of probes, and discuss pros and cons compared to
using hierarchy names (Section 11.3).
11.1 Overview of Elaboration
The process of elaboration, where a EOO model is translated into an equation system can
informally be described to perform at least the following three main activities:
• Type checking of models. Check that parameterized models conform to the type
rules of the language and that basic operations and function calls are type correct.
159
160
11
Elaboration Semantics
For example, a function having one argument cannot be applied to two arguments
and a plus operator cannot have a string as its left operand and an integer as its right
operand, etc.
• Collapsing the instance hierarchy. During this activity, new unknowns and equations are created for sub-components of a model. For example, if a model contains
two resistors R1 and R2, where R1 is parameterized with 10 ohm, and R2 with 50
ohm, two equations are created u1 = 10 * i1 and u2 = 50 * i2. Moreover, unknowns, such as the voltage drop over the components must be different
for the components. Hence, u1 and u2 must be different unknowns.
• Connection semantics. Acausal ports contain flow and potential variables, where
the former must sum-to-zero at connection points and the latter must have the same
potential at the connection point. This activity generates equations and unknowns
to enable acausal modeling.
In Modelica, all these three activities are typically performed at compile time in a Modelica compiler. In the Modelica specification, it is not specified in which order the activities
should be performed. Commonly, the two first activities are performed together, while
the last one could be performed in a separate phase.
MKL separates these activities into distinct phases. These activities are performed at
different point in time during the process:
1. Type checking is performed at compile time by the MKL compiler (or before evaluation in an interpretive setting).
2. Collapsing the instance hierarchy is performed at runtime when executing the MKL
program.
3. Connection equation generation is generated at runtime by a user defined function
that performs intensional analysis (inspects) the equation system of the model.
We will now briefly discuss the first two activities and then give a detailed description of
the connection semantics in Section 11.2.
11.1.1 Type Checking of Models
Of the described activities in the elaboration process, only type checking is performed at
compile time (or before evaluation in the interpretive setting). Because EOO models in
MKL are ordinary functions defined in an MKL program, type checking of a model is the
same as type checking a program.
For example, recall the Mechsys model described in Chapter 8:
let MechSys =
let r1:Rotational in
let r2:Rotational in
let r3:Electrical in
DCMotor r1;
Inertia 0.2 r1 r2;
FlexibleShaft 120 r2 r3
11.2 Connection Semantics
161
The type checker will report a type error for argument r3 on the last line saying that a
rotational node was expected, but an electrical node supplied. Note that we have in this
example changed the type of the definition of node r3 to be Electrical.
This kind of type errors is caught by the MKL compiler, even if the DSL for the
mechatronic domain was defined as a library in MKL itself. We have specified and discussed the type system for performing these checks in Chapter 10.
Note that certain kinds of checks are currently not performed directly by the type
checker. One such example is constraint delta checking, as presented in Chapter 6. This
checking can of course be performed at the equation level using intensional analysis on
the model, but in such a case we loose the property of isolating and locating the source
of the error - one of the main benefits of the constraint delta approach. We see it as a
challenge and future work to incorporate such a checking at the kernel language level,
without being dependent on properties of the DSL.
11.1.2 Collapsing the Instance Hierarchy
A model abstraction in MKL is created using ordinary higher-order functions. Creating
an instance of a model means passing arguments to the model so that an equation system
can be generated. For example, the type signature for the Resistor model is
Real -> Electrical -> Electrical -> Equations
Hence, by applying Resistor to three arguments (the resistance instance and two electrical nodes), the function will be computed and an equation system will be returned.
Consequently, the formal semantics for collapsing the instance hierarchy is defined by the
operational dynamic semantics described in Chapter 10.
11.2 Connection Semantics
The connection semantics, i.e., the ability of the EOO language to handle acausal connections, is handled differently in different languages. We will in this section formalize
the semantics of generating correct equations and unknowns for MKL. This semantics is
different from the Modelica semantics in several aspects. However, we will see that they
both give the same semantic behaviour, i.e., that we can define the same kind of components and that the generated equation systems give the same solution after simulation.
11.2.1 A Minimal Circuit in Modelica
Let us first give an intuition for the Modelica approach of describing connection semantics. Figure 11.1 shows a graphical view of the circuit. The circuit contains a direct current
constant voltage source DC, a resistor R, and a ground G. The figure shows a visualization
of unknowns and their location after elaborating the components with a Modelica compiler. Both the voltage source and the resistor have a positive connector1 p (filled square)
and a negative connector n (unfilled). The ground only has a positive connector. Each
connector creates two variables: i for current and v for voltage. These are defined in the
connector class:
1 Remember
that in Modelica ports are called connectors
162
11
Elaboration Semantics
Figure 11.1: A minimal electrical circuit modeled using Modelica. To the right of
each component the unknowns are stated using dot notation, e.g., DC.p.v is the
potential variable for the positive connector in the DC component.
connector Pin
Real v;
flow Real i;
end Pin;
We use the prefix notation for defining variables, as customary in Modelica. For example
unknowns R.p.v and R.p.i define the two unknowns in the positive pin of resistor R.
The four unknowns DC.v, DC.i, R.v, and R.v are defined by the base class TwoPin
model TwoPin "Superclass of components"
Pin p, n;
Voltage v;
Current i;
equation
v = p.v - n.v;
0 = p.i + n.i;
i = p.i;
end TwoPin;
This base class is also contributing 3 equations. The first one defines the voltage drop
over the component. The second one states that the current p.i in the positive connector
should be equal but with opposite sign compared to the current in the negative connector
p.n. The reason for the opposite sign is Modelica’s convention that connectors always
describe the positive direction of flow into the component. The last equation i = p.i
states that the current in the circuit is the same as the current flowing into the circuit. The
TwoPin class generates the following equations for the voltage source
DC.v = DC.p.v-DC.n.v;
0 = DC.p.i+DC.n.i;
DC.i = DC.p.i;
and for the resistor
R.v = R.p.v-R.n.v;
11.2 Connection Semantics
163
0 = R.p.i+R.n.i;
R.i = R.p.i;
Each of the models also contribute one specific equation describing the behavior of the
component. For example, in the resistor case it is Ohm law
model Resistor "Ideal electrical resistor"
extends TwoPin;
parameter Real R "Resistance";
equation
R*i = v;
end Resistor;
generating equation
200*R.i = R.v;
Similarly the constant voltage source
model ConstantVoltage "Source for constant voltage"
parameter Real V "Value of constant voltage";
extends Interfaces.TwoPin;
equation
v = V;
end ConstantVoltage;
generates the equation
DC.v = 12;
Finally, the ground model
model Ground "Ground node"
Interfaces.Pin p;
equation
p.v = 0;
end Ground;
contributes with one equation after elaboration
G.p.v = 0;
We have so far 14 unknowns but only 9 equations. There are obviously 5 equations
missing because the number of equations and unknowns must match. In the top circuit
definition
model MiniCircuit
Resistor R(R=200);
Ground G;
ConstantVoltage DC(V=12);
equation
connect(DC.p, R.p);
connect(G.p, DC.n);
connect(DC.n, R.n);
end MiniCircuit;
164
11
Elaboration Semantics
we have three connect-equations, from which we shall generate new equations. According to Kirchhoff’s current law, the sum of current flowing into a node is equal to the
sum of current flowing out, i.e., the current should sum-to-zero. Because the connection
relationships between components are in Modelica given by binary connect-equations,
the compiler should first form connection 2 sets. Also, for each connector part of the set,
information should be provided if the connector is connected from the outside or the inside, called outside connectors and inside connectors. In this simple case, all connectors
are inside connectors because all the component that are connected are located inside
circuit MiniCircuit.
We now have two connection sets, corresponding to connection nodes e1 and e2. The
first connect-equation connect(DC.p, R.p) generates the set {DC.p, R.p}, and
the second two connect-equations the set {G.p, DC.n, R.n}. Note that the first set
are all connected to node e1 and the second set to node e2. Note also that if there would
have been a fourth connect-equation connect(G.p, R.n), the same connection set
should have been generated.
According to the language specification, equations shall be generated so that potential
variables (voltage) are equal. Hence, for a set with cardinality n, n − 1 equations need to
be generated. In the first set {DC.p, R.p}, corresponding to node e1, the equation
R.p.v = DC.p.v;
is generated, and for the second set {G.p, DC.n, R.n}, the equations
G.p.v = DC.n.v;
R.n.v = DC.n.v;
are generated. Following Kirchhoff’s current law, the sum-to-zero equation for node e1
is
DC.p.i+R.p.i = 0;
and for node e2
DC.n.i+G.p.i+R.n.i = 0;
Note that all unknowns for the currents can have positive sign because Modelica defines
the direction of flow to always be positive into the component.
11.2.2 A Minimal Circuit in MKL
Let us first summarize a number of observations from the Modelica example:
• Equations that are describing the behavior of a component, for example Ohm’s law
200*R.i = R.v or the definition of the constant voltage DC.v = 12 relate to
the current flowing through the component, or the voltage drop over the component. The exception is the ground component, where the unknown of the connector
was explicitly accessed, i.e., the equation G.p.v = 0.
2 It is called connection sets in the Modelica specification, but should probably be connector sets. However,
to be compliant with the Modelica specification, we still use the term connection set.
11.2 Connection Semantics
165
Figure 11.2: A minimal electrical circuit visualized graphically. To the right of
each component the unknowns for a corresponding MKL model are stated. The
arrows surrounding the nodes indicate the direction of how the sum-to-zero equation
is computed.
• The unknown for voltage in connectors that are connected, e.g., R.p.v and DC.p.v
always denote the same value and this value always correspond to a connection
node (e.g. e1), which in turn corresponds to a connection set.
• The number of sum-to-zero equations that are generated is equal to the number of
connection nodes in the circuit, assuming that all connectors are connected.
Let us now walk through the same mini circuit example using the MKL approach for
connections. Consider the following top level code for model MiniModel.
let MiniCircuit =
let e1:Electrical in
let e2:Electrical in
Resistor 200. e1 e2;
ConstantVoltage 12. e1 e2;
Ground e2
The first observation to be made is that we do not have any connect-equations. Instead,
we connect the components by supplying nodes to the component. A node, just like most
other constructs in MKL, is simply an unknown with a specific type. In the electrical
domain, nodes are defined with type Electrical, which is defined in the standard
library file electrical.mkl.
type ElectricalNode
type Electrical = <ElectricalNode>
Hence, the type Electrical is a type alias for the node model type. Because
ElectricalNode is a user defined type, it can be recognized using pattern matching
during intensional analysis of the model.
Models are, as previously discussed, defined as functions. For example, the model
166
11
Elaboration Semantics
let Resistor R:Real -> p:Electrical -> n:Electrical -> Equations =
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
R *. i = v
takes the resistance, as well as two electrical nodes as input. The goal of the elaboration
process is to get a set of equations, and because the return type of these models is the type
Equations, applying the model to its arguments, including the nodes, is the same as
model instantiation. Note that this is possible because unknowns are first class and nodes
are unknowns.
Now, consider Figure 11.2. In this case, we have only 6 unknowns, each corresponding to the current flow through the connector (e.g., DC_i, R_i, and G_i) and the voltage
drop over the component (and DC_v, R_v, and G_v). We use the underscore notation
to make a distinction from the Modelica example. These unknowns are the unknowns
explicitly defined in the Resistor model, the ConstantVoltage model
let ConstantVoltage V:Real -> p:Electrical -> n:Electrical ->
Equations =
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
v = V
and the Ground model
let Ground p:Electrical -> Equations =
let i:Current in
let v:Voltage in
ElectricalRefBranch i v p;
v = 0.
Contrary to the Modelica semantics, we have no connectors that define unknowns. The
ports, by contrast to Modelica’s connectors, are just normal formal parameters to which
unknowns can be passed, which are here representing nodes.
Recall now our earlier observation that all potential variables in a connection set corresponds to the same unknown and that each connection set corresponds to one node.
Hence, we give our first informal rule for the node elaboration
Rule 1 - Unknown potentials: for each node in the circuit, create an unknown representing the potential in the node.
Following this informal rule on the nodes e1 and e2 in Figure 11.2, we generate two
more unknowns, denoted
e1_v
e2_v
The earlier observation also stated that we shall generate a sum-to-zero equation for each
node due to Kirchhoff’s current law . However, we must with great care choose signs
for the currents. This is our first use of the definitions of branches. In both the voltage
source and in the resistor, we have a definition of ElectricalBranch. The intuition
11.2 Connection Semantics
167
of a branch is that it states the path of flow through a component between two nodes. It is
defined in the standard library file electrical.mkl:
let ElectricalBranch :
<Real -> Real -> ElectricalNode -> ElectricalNode -> Eqs>
Hence, an electrical branch is also an unknown defining a function model type. Consider
again the definition inside Resistor. The first argument to ElectricalBranch is
the unknown current, the second argument the unknown voltage. The third argument is
the positive node and the fourth argument the negative node. Hence, by matching on the
branch, we can decide if the branch is pointing with its positive or negative side towards
a node. From this follows the third rule:
Rule 2 - Sum-to-zero equations: For each node n in the circuit, create a
sum-to-zero equation, such that the unknown flow variables for the branches
connected to node n get a positive sign if the branch is pointing in the positive
direction to the node, and a negative sign if it is pointing in the negative
direction. For reference branches, the positive sign is always used.
In Figure 11.2, the direction of the branches are marked as arrows in the components.
Using this approach, we generate two sum-to-zero equations for the example:
DC_i +. R_i = 0.
-.DC_i -. R_i +. G_i = 0.
In the ground model, we have an ElectricalRefBranch, defined as follows
let ElectricalRefBranch : <Real -> Real -> ElectricalNode -> Eqs>
The ref branch takes an unknown current and an unknown voltage as inputs, but only one
node. Such a node can be seen as branch for directly accessing the reference values of
node. In the case of the ground component, this unknown is reference in the sum-to-zero
equation, but not in any other equations.
We have now two potential unknowns for the nodes e1 and e2 and two sum-to-zero
equations. However, each of the components has two unknowns resulting in six unknowns
that do not have any related equation. The first three of the missing equations are already
defined explicitly in the model defining the components behavior. These are:
200. *. R_i = R_v
G_v = 0.
DC_v = 12.
Hence, we now have in total 8 unknowns and 5 equations. What equations are missing?
The equations defining the voltage drop over the component:
Rule 3 - Relative potential equations: For each branch in the circuit, create
an equation stating the voltage drop between the unknowns defined for the
connected nodes. For reference branches, state that the voltage drop is equal
to the potential of the connected node.
Following Rule 3, we get
168
11
Elaboration Semantics
R_v = e1_v -. e2_v
DC_v = e1_v -. e2_v
G_v = e2_v
We now have 8 equation and 8 unknowns. Why did we get 8 equations while the
Modelica compiler generated 14 equations? First, in Modelica, several unknowns are
generated for the same potential variable, representing the same node. In this case, 4
unknowns were generated, instead of two that are needed in the MKL semantics, i.e., 2
more unknowns. Secondly, the current unknowns are both represented for the flow inside
the component as well as through the connectors in Modelica. In total, this is 4 more
unknowns and corresponding equations in Modelica. Note that the ground component
includes the two unknowns in both cases.
After this informal introduction, we are now ready to formalize the connection semantics.
11.2.3 Formalization of the Connection Semantics
Let N be a finite set of nodes and n ∈ N denote a node element. Let U be a finite set
of unknowns and u ∈ U an unknown. A branch is a quadruple (uf , urp , n1 , n2 ) ∈ Bbin ,
where uf is a flow unknown, urp a relative potential unknown, n1 a first and n2 a second
node connected to the branch. Let (uf , urp , n1 ) ∈ Bref be a reference branch, where
uf is the flow unknown, urp a relative potential unknown, n1 a connected node. Set
Bbin is the set of binary branches and Bref is a set of unary reference branches. Let
B = Bbin ∪ Bref denote a set of all branches. Let the pair (n, up ) ∈ P denote the
potential unknown associated with node n, and let P be the set of such pairs. We define
an expression e and a list of equations E with the grammar rules
e ::= e + e | e - e | 0 | u
E ::= (e = e) · E | ε
where + and - are plus and minus operators, 0 the value zero, and u an unknown. The
term (e = e) · E is the cons of an equation onto an equation list, ε is empty list.
Figure 11.3 defines the connection elaboration semantics as a set of recursive function
definitions. Each of the functions is categorized according to the informal rules described
in the previous section.
In Rule 1. unknown potentials are generated for each node. A function ukpot is
defined, which takes a tuple as input, where the first element N is the set of nodes and the
second element U a set of unknowns. The set U is used for generating unique unknowns.
The function returns a set P , i.e., a mapping (n, up ) between the nodes and the new
unknowns representing potential values. The function is total when the guard u ∈
/ U is
interpreted as generating a new fresh u that is not in the set U .
In Rule 2, a list of sum-to-zero equations are generated. It consist of one main function sumzero and one help function sumexpr. The function sumzero takes a tuple as
input, where the first element N is the set of nodes and the second element B the set of
branches. For each n ∈ N , the function creates the sum-to-zero expression using the
help function sumexpr. The first three cases of the body consider binary branches by
matching on the quadruple (uf , urp , n1 , n2 ). Only nodes that are directly connected to
169
11.2 Connection Semantics
ukpot(N, U )
Rule 1 - Unknown potentials
ukpot(∅, U )
ukpot(N, U )
=
=
∅
ukpot(N − {n}, U ∪ {u}) ∪ {(n, u)}
if n ∈ N and u ∈
/U
sumzero(N, B)
Rule 2 - Sum-to-zero equations
sumzero(∅, B)
sumzero(N, B)
=ε
= (sumexpr(n, B) = 0) · sumzero(N − {n}, B)
if n ∈ N
sumexpr(n, B)
sumexpr(n, ∅)
=8
0
>
>
>
>
>
>
>
>
>
>
>
>
<
sumexpr(n, B ∪ {b}) =
>
>
>
>
>
>
>
>
>
>
>
>
:
sumexpr(n, B − {b}) + uf
sumexpr(n, B − {b}) - uf
sumexpr(n, B − {b})
sumexpr(n, B − {b}) + uf
sumexpr(n, B − {b})
if (uf , urp , n1 , n2 ) = b and
n = n1 and n 6= n2
if (uf , urp , n1 , n2 ) = b and
n 6= n1 and n = n2
if (uf , urp , n1 , n2 ) = b and
((n 6= n1 and n 6= n2 ) or
(n = n1 and n = n2 ))
if (uf , urp , n1 ) = b and n = n1
if (uf , urp , n1 ) = b and n 6= n1
relpot(P, B)
Rule 3 - Relative potential equations
relpot(P, ∅)
=8
ε
(urp = up1 - up2 ) · relpot(P, B − {b})
>
>
>
>
<
relpot(P, B ∪ {b}) =
>
>
> (urp = up1 ) · relpot(P, B − {b})
>
:
conelab(N, B, E, U )
Connection elaboration
conelab(N, B, E, U )
if (uf , urp , n1 , n2 ) = b
and (n1 , up1 ) ∈ P
and (n2 , up2 ) ∈ P
if (uf , urp , n1 ) = b
and(n1 , up1 ) ∈ P
=
(E ′ , U ′ )
if P = ukpot (N, U )
E ′ = E ⊕ sumzero(N, B) ⊕ relpot(P, B)
U ′ = U ∪ {u | (n, u) ∈ P }
Figure 11.3: Formalization of MKL’s connection semantics.
the considered branch are added to the expression. The last two cases handles reference
branches in the same manner. Note that a 0 expression is inserted at the end of the recur-
170
11
Elaboration Semantics
sion. This zero expression can easily be eliminated by also introducing unary minus in
the expression. However, it makes the definition less readable and is therefore avoided in
this formalization.
In Rule 3, we generate the relative potential equations. In the electrical domain this
corresponds to the voltage drop over a component. The function relpot takes a tuple as
argument where the first element is a set P consisting of the tuple (n, up ) ∈ P , where n
is a node and up a potential unknown associated with the node. For each branch, we pick
out the associated potential unknowns for the connected nodes. The list of equations is
generated recursively.
Finally, the last function definition conelab takes a quadruple as argument. The first
element N is the nodes of the model and the second element B the branches. The third
element E is a list of equations that already exist in the model, e.g., equations such as
Ohm’s law. The fourth element are the unknowns defined in the circuit, e.g., the current
flowing through a component or the voltage drop over a component. The function returns
a tuple consisting of the elaborated list of equations and all unknowns of the model. Note
that we are using the symbol ⊕ for an infix left associated list append operator.
We define the following limitations on what can be considered valid input to the
conelab function.
Proposition 11.1 (Valid input for connection elaboration)
For a valid input quadruple (N,B,E,U) holds
1. If (uf , urp , n1 , n2 ) ∈ B then {uf , urp } ⊆ U and {n1 , n2 } ⊆ N
2. If (uf , urp , n1 ) ∈ B then {uf , urp } ⊆ U and n1 ∈ N
Note that nodes that are not connected to a branch are allowed as input, but will result in
equations of form 0 = 0, which should be discarded.
11.2.4 Composition, and Multiple States
We will now discuss the connection semantics for when parts of a model are used to construct a new model. Consider Figure 11.4, which consists of three circuits. Figure 11.4a
shows a simple circuit called CircuitA, where an inductor and a capacitor is connected
in parallel, which are in turn connected in series with a resistor. These three components
are composed into another model, illustrated in Figure 11.4c. The new model has two
ports (or connectors) to which the internal components are connected. Finally, in Figure 11.4b, we show a new model named CircuitB where an instance of the new model
is created and then connected. Hence, CircuitA and CircuitB models the exact
same circuit, but abstracted in different ways.
Elaborating with Modelica
When elaborating CircuitA in Modelica, we get an equation-system containing 27
equations and 27 unknowns. However, when elaborating circuit CircuitB, we get 32
equations and 32 unknown. When we simulate the two circuits, we see that they get the
exact same simulation result. Why are then 5 more equations generated for CircuitB
11.2 Connection Semantics
171
Figure 11.4: Illustration how parts of a circuit can be composed into a new model
abstraction. Figure (a) shows the full circuit and Figure (c) shows how three of the
components are composed into a new model. Figure (b) shows how an instance of
the model in (c) is used. At the end, the models in Figure (a) and Figure (b) model
the same circuit.
than CircuitA? The reason is that the abstracted model now contains two new connectors, each contributing with two unknowns. The last new unknown is the voltage drop
over component M.
In CircuitB, the Modelica connect semantics need to take into consideration if
connectors are inside or outside connectors. The same connector can both be an inside
and outside connector, depending on if the current connection set are elaborated from the
inside or the outside of a component. When CircuitB is elaborated, it starts by first
elaborating its sub-components. When the SC component is elaborated, the connections
between the components R, C, and L are elaborated. In the case of equations for potential
variables, there is no difference, e.g., the equation between SC’s positive connector and
the resistor is
SC.p.v = SC.R.p.v;
Similarly, between the resistor R, the inductor L and the capacitor C, two equations are
generated to make the potential equal
SC.L.p.v = SC.C.p.v;
SC.R.n.v = SC.C.p.v;
For the sum-to-zero equations, it is a bit different. First, consider equation
SC.C.p.i+SC.L.p.i+SC.R.n.i = 0;
which is the sum-to-zero equation for the connection set between components SC.R,
SC.L, and SC.C. All the connected connectors are here inside connectors because the
connectors belong to components that are inside the model that is currently elaborated.
172
11
Elaboration Semantics
The opposite, an outside connector, is an connector that is connecting to the outside of
the model. Consider the following equation:
(-SC.p.i) + SC.R.p.i = 0;
This is the sum-to-zero equation between component SC’s positive connector (an outside
connector) and resistor SC.R’s positive connector (an inside connector). According to
the Modelica specification, outside connectors shall have negative sign. The reason for
this is to make the signs right when connecting the new component.
Elaborating with MKL
Now, let us consider CircuitA modeled in MKL:
let CircuitA =
let ee1:Electrical in
let ee2:Electrical in
let e1:Electrical in
Resistor 150. ee1 e1;
Inductor 0.1 e1 ee2;
Capacitor 0.01 e1 ee2;
SineVoltage 220. 50. ee1 ee2;
Ground ee2
When elaborating this model, we get 13 equations and 13 unknowns. This is approximately half of the 27 equations generated for CircuitA in Modelica. We simulate and
check that the both circuits give the same behavior. The reason for the differences is again
that MKL does not have unknowns in the ports.
Now, if we compose the three sub-components Resistor, Inductor, Capacitor into another model
let SubComponent p:Electrical -> n:Electrical =
let e1:Electrical in
Resistor 150. p e1;
Inductor 0.1 e1 n;
Capacitor 0.01 e1 n
and then use this in CircuitB we have the following model:
let CircuitB =
let ee1:Electrical in
let ee2:Electrical in
SineVoltage 220. 50. ee1 ee2;
SubComponent ee1 ee2;
Ground ee2
When elaborating CircuitB we get 13 equations and 13 unknowns. Hence, for both
model CircuitA and CircuitB, MKL gives 13 equations, but in the Modelica case,
CircuitA gave 27 equations and CircuitB 32 equations. Why is not CircuitB
generating more equations in the MKL case? Because the elaboration semantics of MKL
does not generate new equations when models are composed. The reason for this is as
follows:
11.2 Connection Semantics
173
Consider again model the SubComponent. The body of the model is almost exactly
the same as line 4-7 in model CircuitA. The difference is only the name of the nodes.
When the model SubComponent is instantiated in CircuitA, the nodes ee1 and
ee2 are supplied to the function and then substituted into the body of SubComponent.
Hence, after collapsing the instance hierarchy of the model, and before connection elaboration is performed, the models CircuitA and CircuitB are equivalent.
Models with Several States
In certain domains and for certain models the model should have different flow values on
different sides of the component. In Modelica this is implicitly solved because the connectors have their own flow variables. However, because the corresponding MKL model
only has one flow variable for each branch, which is given by the ElectricalBranch,
it would perhaps be hard to model such domain models. Fortunately, this not the case.
A typical example when this occurs is when modeling rotational 1D mechanics. Example models are inertia and ideal gear. Let us study the latter a bit closer. An ideal gear
can be modeled as follows, by following the conventions in the Modelica standard library:
let IdealGear ratio:Real -> flangeA:Rotational ->
flangeB:Rotational -> Equations =
let tauA:Torque in
let tauB:Torque in
let phiA:Angle in
let phiB:Angle in
RotationalRefBranch tauA phiA flangeA;
RotationalRefBranch tauB phiB flangeB;
phiA = ratio *. phiB;
0. = ratio *. tauA +. tauB
In an ideal gear, both the torque and the angle at each side should be different. The linear
relationship is given by the parameter ratio and the relation is modeled by the two last
equations. Instead of having one branch over the component, we define two reference
branches and thus generate unknowns for both flangeA and flangeB. Recall the connection semantics in Section 11.2.3. In the case of a reference branch in the mechanical
domain, the angles phiA and phiB, which are the potential variables, will be equal to
the connected node. Hence, phiA and phiB will be the absolute angles for flangeA
and flangeB. The flow variable in the reference case, i.e., the torques tauA and tauB
represent the flow at each side of the component.
11.2.5 Executable Specification
In MKL, intensional analysis of models can be used to inspect the equation system. Also,
new models can be created by synthesizing new models. Hence, we can transform a
model A into a model B according to some transformation rules.
We will now demonstrate this principle by creating an executable specification of the
connection semantics. The elaboration semantics is defined in the standard library file
elaboration.mkl and can be found in Appendix D.7. The full executable specification corresponding to the definition in Section 11.2.3 fits approximately into two and a
174
11
Elaboration Semantics
half page of source code. Hence, we would also like to demonstrate that the functional
style of transforming a model can be considered as an expressive alternative.
The implementation is pure functional and declarative with the exception of the generation of unknowns, which is part of the MKL semantics. There are also some differences
in this executable specification compared to the formal definition in Section 11.2.3. The
most important one is performance. Implementing the formal definition as defined in the
previous section is possible, but generates a very slow solution that does not scale. The
main reason is that for each node n ∈ N in the function sumzero, the function sumexpr
is called and then recursively applied for each b ∈ B. Hence, we can directly say that the
asymptotic lower bound is Ω(|N ||B|) which is not scalable for an executable solution.
We will now walk through the source code for the connection semantics function by
function. First, consider the header of the main function:
let elaborateConnections isBranch:(<> -> Bool) ->
isRefBranch:(<> -> Bool) ->
model:Equations ->
Equations =
The function elaborateConnections takes as its first two arguments two predicate
functions, used to check if a certain branch is a branch or not. For example, when used in
the mechatronic domain, the first function that could be supplied is
let isMechatronicBranch b:<> =
match b with
| ’ElectricalBranch -> true
| ’RotationalBranch -> true
| _ -> false
By separating out this predicate, the function elaborateConnections can easily be
used for different domains. The third formal parameter is a model of type Equations.
We know that a system of equations is a MKL model and that we therefore can inspect
this data. The return type is also Equations, hence we define a model transformation,
where both the source and target models are of the same type.
The function elaborateConnections contains several local functions. Consider
the first helper function:
let addNode node:Node -> nodemap:NodeMap -> NodeMap =
if Map.mem node nodemap then nodemap
else let u:<Real> in Map.add node u nodemap
in
which uses type aliases3
type Node = <>
type Unknown = <>
type NodeMap = (Node => Unknown)
The function addNode takes a node as input and if it does not exist as a key in the node
map, it is added with a new fresh unknown of type <Real>. This function will be used
when looking up nodes in the model and then to create unknown potentials for that node
3 Type
aliases does not give any improved type checking, but makes the code more readable.
11.2 Connection Semantics
175
(recall Rule 1). The function also makes sure that if an unknown potential is already
created for the node, it will not create a new one.
The next function defines the generation of sum-to-zero expressions
let sumexpr branches:BranchSet -> ExprMap =
let worker branches:BranchList -> emap:ExprMap -> ExprMap =
match branches with
| (b i v p n)::bs when isBranch b ->
let emap1 = if Map.mem p emap
then Map.add p ((Map.find p emap) +. i) emap
else Map.add p i emap in
let emap2 = if Map.mem n emap1
then Map.add n ((Map.find n emap1) -. i) emap1
else Map.add n (-. i) emap1 in
worker bs emap2
| (b i v p)::bs when isRefBranch b ->
let emap1 = if Map.mem p emap
then Map.add p ((Map.find p emap) +. i) emap
else Map.add p i emap in
worker bs emap1
| [] -> emap
in worker (Set.toList branches) (Map.empty)
in
Five new type aliases are used in this function
type
type
type
type
type
Expr = <>
Branch = <>
ExprMap = (Node => Expr)
BranchSet = (Set Branch)
BranchList = [Branch]
The function sumexpr takes a set of branches as input and returns a map where the key is
a node and the value is an expression. The local function worker takes a list of branches
and the expression map (node to expression) and creates a new expression map. The function implements sumexpr in Rule 2 for sum-expressions, i.e., it matches either a binary
branch (first match case) or a reference branch (second match case). Note that the model
function b is here a pattern variable and the check that it is a branch is done in the when
guard, by calling the predicate function isBranch. The function isBranch is a formal
parameter to the main function elaborateConnections. Note that this variable is
accessible because sumexpr is a local function to elaborateConnections.
The pattern variable i is the flow unknown and v is the relative potential unknown.
We use the naming convention for the electrical domain here, but the elaboration function
is not specific to that domain. The last pattern variables p and n are the positive and
negative nodes connected to the branch.
The main activity that the match cases do is to first check if an expression exists for
the node. If it exists, a new expression is created, where the current is added
Map.find p emap) +. i
in the case when the node is connected to the positive side of the branch, and subtracted
176
11
Elaboration Semantics
(Map.find n emap1) -. i
in the case when it is connected to the negative side of the branch. Note that because both
the value returned from (Map.find n emap1) and variable i are model types, this
whole expression will be a model type.
Note also that the insertion of new expressions is purely functional, i.e., we use the
ADT Map which implements a declarative map container. Insertion and lookup of values
for the Map ADT has O(logn) complexity, where n is the number of elements in the map.
The actual generation of sum-to-zero equations is performed by the sumzero function:
let sumzero m:Equations -> branches:BranchSet -> Equations =
let worker elist:ExprList -> Equations =
match elist with
| (_,e)::es -> e = 0.; worker es
| [] -> m
in worker (Map.toList (sumexpr branches))
in
The function sumzero calls sumexpr, generates a list of expressions and then creates
sum-to-zero equations directly. An informal analysis gives the asymptotic upper bound
complexity for sumzero to be O(|B| log|B|), where |B| is the number of branches.
The improvement, compared to the formal definition in Section 11.2.3 is that the function
sumzero only performs one pass over the branches and during this pass inserts and adds
elements to a map at O(log |B|) time. We know that the size of the expression map returned from sumexpr is smaller or equal to the size of the branch set called branches,
because each step in the recursion in sumexpr is at most adding one element. Hence,
the iteration over the expression list in sumzero does not make the complexity worse.
The last local function for the connection elaboration is the function potentials:
let potentials model:Equations -> (Equations,BranchSet) =
let worker m:Equations -> nodemap:NodeMap ->
branchset:BranchSet -> (<>,NodeMap,BranchSet) =
match m with
| b i v p n when isBranch b ->
let nodemap2 = addNode n (addNode p nodemap) in
let eq = (v = (Map.find p nodemap2) -.
(Map.find n nodemap2)) in
(eq,nodemap2,Set.add m branchset)
| b i v p when isRefBranch b ->
let nodemap2 = addNode p nodemap in
let eq = (v = (Map.find p nodemap2)) in
(eq,nodemap2,Set.add m branchset)
| e1 ; e2 ->
let (e1b,nodemap1,branchset1) =
worker e1 nodemap branchset in
let (e2b,nodemap2,branchset2) =
worker e2 nodemap1 branchset1 in
(e1b ; e2b, nodemap2, branchset2)
| _ -> (m,nodemap,branchset)
in
11.3 Extracting Model Information
177
let (model,_,branchset) =
worker model (Map.empty) (Set.empty)
in (model,branchset)
in
The function potentials generates both new potential unknowns for the nodes (Rule
1) and adds relative potential equations (Rule 3). The local function worker recursively traverses the equation system (third case with pattern e1 ; e2). The first two
match cases match a binary branches and reference branches respectively. The function
addNode is now used to add both the positive and the negative nodes to the node map
(described earlier). The values of this map are the new potential unknowns. The only
equations that reference the potential unknowns are the relative potential equations generated in the first two match cases, e.g., the line
let eq = (v = (Map.find p nodemap2) -.
(Map.find n nodemap2)) in
from the first match case. We create a new equation bound to the variable eq. The new
equation includes the unknowns looked up in nodemap2, which are associated to the
corresponding nodes.
The last part of function elaborateConnections makes use of the locally defined functions described above:
let (model2,branchset2) = potentials model in
sumzero model2 branchset2
First, function potential is applied to the model supplied to the main elaboration function. A transformed model is returned, which includes new relative potential equations
together with unknown potentials for the nodes. Function potentials also returns the
branchset for the model. This set is then later used in function sumzero for generating
the sum-to-zero equations. Hence, only function potential needs to traverse the equation system. The function sumzero adds the new sum-to-zero equations on top of the
equation system of model2 and returns the final system of equations.
11.3 Extracting Model Information
A mathematical model can be used for several different things. The application area
that we have discussed mostly in this thesis is for simulation. However, if a model after
elaboration consists of thousands of equations, there must be a strategy for how to extract
for example the simulation results of a particular variable, e.g., for the purpose of plotting.
We call this the model information extraction problem.
11.3.1 Hierarchy Naming vs. Probing
There are several approaches for solving the model information extraction problem, which
all have their pros and cons. We see two main alternatives for extracting information as
the result of using a model:
1. Hierarchy naming where all unknowns in the model have a unique textual name
that can be used for identifying the corresponding unknown.
178
11
Elaboration Semantics
2. Probing with a language construct for “probing” information from particular unknowns in the model. The probes are added into the model.
The first approach, hierarchy naming, is used in, e.g., Modelica. For example, assume
that a main model Circuit has as a sub-component a resistor component called R. A
resistor model has a variable called v, which defines the voltage drop over the component.
Hence, when the model is elaborated into an equation system, the unknown for the voltage
drop has the name Circuit.R.v. Hence, Modelica tools, such as Dymola [45] or
MathModelica [91] support a tree browser view after simulation, where the user can click
on different variable names to inspect the simulation result.
The alternative approach, which we call probing is when an element, a “probe”, is
added to the model, which indicates which unknown should be extracted. This could
be done both visually using a GUI or textually, by inserting a language statement or
expression. For example, MapleSim [90] is using this approach.
We see both pros and cons with both alternatives. With the hierarchy naming approach, each unknown has always a unique name that can be understood by a user. However, for large models with thousands of equations and several levels in the hierarchy, it
can become fairly hard to get an orientation by looking at variable names in a tree view.
The main problem with this approach is that the tree view for inspecting the variable
names is not the same view as the one for the source code because it is created according
to the instance hierarchy. However, the pros with this approach is that the model does
not need to be altered before simulation. Moreover, the decision of which variables that
should be inspected can be postponed to after the simulation.
The alternative of using probes forces the user to modify the model before simulation. However, with good software tool support, this does not necessarily mean that it is
cumbersome for the user. A benefit with this solution is that the user has the same view
for both modeling and the variables that should be inspected. In the simplest case, probes
need to be inserted before simulation. However, if the model is compiled in a kind of
debug mode, it might be possible that these probes can be added after simulation, and
thus making use of the simulation result already available.
A major difference of the two approaches is how open the language’s internal form
should be to the user. To enable hierarchy naming, the names used in the model must be
preserved during simulation. Comparing to ordinary program languages and compilers,
this means that the model must be compiled in debug mode where symbol names are
stored. Moreover, when making use of anonymous functions, it is less clear how this can
be achieved because no names are available at modeling time. An analogy for probes and
programming is that probes can be seen as a way of creating traces in the model, i.e., to
decide in the model what information that should be printed out. Another difference is
their ability to handle variable structured systems, i.e., when the number of equations and
variables change over time. Obviously, this poses new challenges for model information
extraction because the set of unknowns cannot be decided upon compile time.
11.3.2 Modeling with Probes in MKL
The choice of how to extract information from a model is not encoded into the language.
Instead, there are standard libraries which define the way information can be extracted.
11.3 Extracting Model Information
179
Direct hierarchy naming is difficult to accomplish in MKL because in the same way as
in other functional languages, the actual identifier name is not important for the computation result. Internally, the compiler and runtime system can be using indexes or pointers
for variable lookup.
Let us consider the LotkaVolterra model again:
let LotkaVolterra =
let growthRateRabbits = 0.04 in
let deathRateRabbits = 0.0005 in
let deathRateFoxes = 0.09 in
let efficiencyGrowthFoxes = 0.1 in
let rabbits:Population in
let foxes:Population in
Init rabbits 700.;
Init foxes 10.;
der(rabbits) = growthRateRabbits *. rabbits -.
deathRateRabbits *. rabbits *. foxes;
der(foxes)
= efficiencyGrowthFoxes *. deathRateRabbits *.
rabbits *. foxes -. deathRateFoxes *. foxes
probe "foxes" = foxes;
probe "animals" = foxes +. rabbits
We have now added two more equations, both with one probe each. The probe construct
is not built into the language. It is defined in the standard library modeling.mkl:
let probe : <String -> Real>
Hence, a probe is an unknown of a function model type. The function takes as input a
String, and returns as result a Real. The string is the name that then later can be
used to identify the unknown, e.g., when plotting the simulation result. Note that we in
the probe "animals" also are probing the value that is the result of adding foxes and
rabbits.
In the LotkaVolterra example, the probes were explicitly referencing an expression using an equation. However, for probing the information from components within a
certain domain, is should be easy to access the information relevant for that domain. Now,
let us consider the MechSys model again:
let MechSys =
let r1:Rotational in
let r2:Rotational in
let r3:Rotational in
DCMotor r1;
Inertia 0.2 r1 r2;
FlexibleShaft 120 r2 r3;
SpeedSensor (probe "omega") r3
In the example, we are using a sensor for extracting the wanted information. These sensors are themselves models and can be used for example to extract speed information, and
then use this information in a feedback loop for a control system. Such sensor models
are also available in the Modelica standard library, and we have modeled here the same
behavior. The definition of the speed sensor is
180
11
Elaboration Semantics
let SpeedSensor w:Signal -> flangeB:Rotational -> Equations =
let phi:Angle in
RotationalRefBranch 0. (-.phi) flangeB;
w = der(phi)
Recall the definition of the Signal type
type Signal = <Real>
i.e, the SpeedSensor gives an output signal of the angular velocity for the node, by
differentiating the signal phi, i.e., the angel. Recall the line
SpeedSensor (probe "omega") r3
of the MechSys model. Here we measure the speed of node r3, which will be the last
node of the 120 elements shaft. We supply a probe called "omega" to the speed sensor,
which results in that we can measure the angular velocity and associate it with the name
"omega".
11.3.3 Elaboration Semantics of Probes
The semantics for how probe information is extracted from a model is defined in the
standard library file elaboration.mkl in Appendix D.7. The source code is listed
below:
type ProbeMap =
(String => [Signal])
let addProbe s:String -> u:Signal -> ps:ProbeMap =
if Map.mem s ps then Map.add s (u::(Map.find s ps)) ps
else Map.add s [u] ps
let elaborateProbes model:Equations -> (Equations,ProbeMap) =
let elab e:<> -> ps:ProbeMap -> (<>,ProbeMap) =
match e with
| ’probe (val s:String) -> let u:Signal in (u,addProbe s u ps)
| e1 e2 ->
let (e1b,ps1) = elab e1 ps in
let (e2b,ps2) = elab e2 ps1 in
(e1b e2b,ps2)
| _ -> (e,ps)
in elab model (Map.empty)
The function elaborateProbes takes an equation system as input and returns a tuple
with the updated equation systems and a mapping of probes. The type ProbeMap is a
mapping between the string values and a list of signals. The strings are the names given
for the probes in the model, and the signals are the unknowns that are associated with
the corresponding probes. Because a model can contain probes with the same names
(e.g., several instances of a model containing a probe with a specific name), we need to
associate a probe name with a list of signals and not just one single signal.
The local function elab recursively traverses the model, both equation systems and
expressions. When a probe is matched (the first match case), we extract the string value
11.4 Chapter Summary and Conclusions
181
s. Then, we create a new unknown u, which is replacing the probe, i.e., the transformed
model will have unknowns where the probes were located.
Recall that in the LotkaVolterra example, we introduced new equations, but no
new explicit unknowns. The unknown is therefore introduced by the probe itself. Similarly, for the SpeedSensor, the probe will introduce a new unknown and supply it
as an argument to SpeedSensor. If we are counting equations and unknowns for the
SpeedSensor, we will see that it is over-determined, i.e., it has one equation too much.
The unknown from the probe restores the balancing.
The actual generation of the probe mapping is handled by function addProbe. This
probe mapping, which is one of the outputs from elaborateProbes, can then be used
by other transformations. For example, if we want to code generate/export the equation
system into another target language, e.g., a flat Modelica form, this probe map can be
used for giving names to variables that should be easily accessible. On the other hand, if
the simulation should be conducted by a library in MKL, the probe mapping can be used
for giving names of the output data of the simulation. Hence, the aim of making the probe
functionality as a separate function is to enable reuse and extensibility of the library.
11.4 Chapter Summary and Conclusions
We have in this chapter given both an informal overview of the elaboration process in
MKL and also formally specified both the connection semantics and how to extract information out of models using probes. We have also given an informal explanation of the
connection semantics in Modelica.
We can see that the connection semantics in Modelica and MKL are different, but
give similar modeling capabilities. Semantically, we argue that the MKL approach is
simpler because it separates the phases of type checking, collapsing the model hierarchy,
and generation of connect equations into distinct phases.
From a modeling point of view, it is of course very subjective which approach is
preferable, e.g., if connect-equations should be used, or if connections are defined by
using nodes. The benefits that we see from a theoretical language point of view is that
the nodes semantics are very natural and fit well into the framework of a typed functional
language based on an effectful extension of the lambda calculus.
182
11
Elaboration Semantics
12
Implementation, Verification, and
Evaluation
Part II we illustrated different aspects of MKL, including several application examples, metaprogramming examples, and formal semantics. In this chapter, we discuss,
verify, and evaluate our solution in relation to the problem area presented in Section 1.3.
The chapter is structured as follows:
I
N
• We give a brief overview of the prototype implementation of MKL and discuss its
current capabilities and limitations (Section 12.1).
• We briefly explain the implementation of two ways of using the model (Section 12.2).
• We explain how the verification of our solution has been performed (Section 12.3).
• We evaluate, discuss, and analyze our approach according to the areas presented in
the problem area: safety aspects, expressiveness aspects and extensibility aspects.
We also briefly discuss some performance aspects of the prototype implementation
(Section 12.4).
12.1 Implementation
The MKL prototype is implemented as an interpreter in OCaml 3.11.2 [74]. The aim of
the prototype at this stage is not to be a full fledged simulation environment that can be
used directly in industry. Instead it is a research prototype used for exploring different
ways of using metaprogramming for EOO languages.
Consider Figure 12.1, which shows a box-and-line diagram for the execution view for
the architecture of the implementation.
A .mkl file is given as input to the left in the figure showing the translation process.
It is translated in a number of sub-phases, followed by evaluation (execution) of the program. If there were no errors during translation and execution, the program outputs its
183
184
12 Implementation, Verification, and Evaluation
Figure 12.1: Outline of the architecture for the MKL prototype implementation.
results and terminates. We call the phases (1) - (5) the static semantics. We say that the
last step (6), evaluation, is described by the dynamic semantics.
12.1.1 File Includer and Symbol Table
The first phase, the file includer, is a simple module system for handling include statements. The file includer first performs lexical and syntax analysis on the input file. The
top-level statements in the file are inspected, one of which is the include statement. For
each include statement, this procedure is recursively performed. The file included by the
include statement is read and lexical and syntax analysis is performed. The process detects
and reports cyclic dependencies between definitions as well as eliminates all duplications
of the top level definitions.
During the lexical analysis new identifiers are detected and added to the global symbol
table (illustrated at the top of Figure 12.1). A unique relationship is created between the
Unicode string of the identifier and an integer value. Two hash tables are defined, one
mapping strings to integers, the other one mapping integer values to strings. During the
static semantics phases, the integer value is used for fast access and comparison. If an
error is detected (the arrows at the bottom of the Figure 12.1) a user message is written
to the standard output, where the string representation of identifiers are looked up in the
symbol table.
12.1.2 Desugaring
The output from the file includer phase is a top-level AST, denoted T-AST. The T-AST
contains the following four top elements:
• let-bindings where a value is bound to a value. This includes top-level function
definitions. For example,
let double x:Int = x * 2
12.1 Implementation
185
• New definition of unknowns. These are constructed in the syntax analyzer when
parsing let-expressions of form let x:T in, where x is the new name and T its
type. For example, the definition of an equation with an unknown equation value
let Eq : <Real -> Real -> Eqs>
• New type declarations of the form type x. For example, the definition of electrical
nodes:
type ElectricalNode
• Type aliases of the form type x= T , where x is the new alias for type T . For
example, the type alias for signals
type Signal = <Real>
Note that include elements are also top-level elements, but these are removed and
processed in the previous phase by the file includer.
Phase (2), called desugar top-level, translates the T-AST into a static analysis AST,
denoted S-AST. Top-level let-style bindings are translated into local definitions, i.e.,
using the in form. Also, new types and type aliases are substituted in all terms following
the definition, so that the all top-level elements are eliminated and an S-AST is returned
as the result.
During this phase, name environments for both types and terms are used when traversing the AST. If a name is not found, a compile time error is reported to the user. The
symbol table and information annotations on the terms are used for good error reporting,
i.e., that the original names are used and line and row number of the error is reported.
The third phase, called pattern compilation, are match-expressions translated into
primitive constructs of the S-AST. The procedure for the pattern compilation is standard and is implemented according to the techniques explained by Peyton Jones and
Wadler [122].
12.1.3 Type Checking and Model Translation
During phase (4), S-AST terms are type checked according to the type systems presented
in Chapter 10. Because the types of formal parameters are explicitly stated in the program, the type checking can be directly performed in a bottom-up fashion on the AST.
During type checking, the AST is also translated so that unknowns cannot be accidentally
evaluated, i.e., terms are lifted to become models, as explained in Chapters 9 and 10.
12.1.4 Program Evaluation after Translation
In phase (5) of the static semantic analysis the S-AST is translated to a runtime AST,
denoted R-AST. In the S-AST, name bindings have been handled by using names and
named environments. Before evaluation, the AST is translated into a nameless representation of terms using a technique invented by de Bruijn in 1972 [46]. Also, the R-AST
also includes closure terms, i.e., terms that contains both a term and its environment. The
evaluation (interpretation) of the program is now performed using a recursive function
defined in OCaml.
186
12.2
12 Implementation, Verification, and Evaluation
Uses of Models
One of the main objectives with the MKL approach is to make it possible to use models
in different ways, and that the semantics for the uses is implemented in libraries. We will
now briefly explain two cases of using the models:
• Exporting the DAE to flat Modelica
• Simulate the DAE
12.2.1 Exporting the DAE to Flat Modelica
After elaborating a model to a DAE, it could sometimes be useful to export the model into
another format. Specific library functions could be written for different target languages,
such as XML or flat Modelica. In this case, we will exemplify the latter.
The whole export source code can be found in the library file
exportmodelica.mkl, available in Appendix D.10.
The aim of the export function is to generate a flat Modelica file, i.e., a Modelica
source code file that only contains equations and variables. For example, if the export
function is executed on the LotkaVolterra model presented in previous sections, the
output is as follows:
model LotkaVolterra
output Real animals = uk3;
output Real foxes = uk2;
protected
Real uk3;
Real uk2;
Real uk1(start=10.,fixed=true);
Real uk0(start=700.,fixed=true);
equation
der(uk0) = (0.04 * uk0 - 0.0005 * uk0 * uk1);
der(uk1) = (5e-05 * uk0 * uk1 - 0.09 * uk1);
uk2 = uk1;
uk3 = (uk1 + uk0);
end LotkaVolterra;
In the protected part of the generated model the four unknowns are named uk0,uk1,uk2,
and uk3. These names are generated by the export functions because unknowns can only
be compared for equality and match the type. The first two equations are the equations
stating the LotkaVolterra dynamics, while the last two equations were given due to probing. At the top, two output variables are given. In this exportModelica function, we
use the probe names to name these output variables. Note also that we use the Init
equations for generating Modelica’s syntax for start attributes.
Consider the following listing of the function for prettyprinting an expression.
let pprintExpr expr:<> -> String =
match expr with
| e1 +. e2 -> "(" ++ pprintExpr e1 ++ " + "
++ pprintExpr e2 ++ ")"
187
12.2 Uses of Models
| e1 -. e2 -> "(" ++ pprintExpr e1 ++ " - "
++ pprintExpr e2 ++ ")"
| e1 *. e2 -> pprintExpr e1 ++ " * " ++ pprintExpr e2
| e1 /. e2 -> pprintExpr e1 ++ " / " ++ pprintExpr e2
| -. e ->
"(-" ++ pprintExpr e ++ ")"
| e1 ^. e2 -> pprintExpr e1 ++ " ^ " ++ "("
++ pprintExpr e2 ++ ")"
| ’der e ->
"der(" ++ pprintExpr e ++ ")"
| ’sin e ->
"sin(" ++ pprintExpr e ++ ")"
| ’cos e ->
"cos(" ++ pprintExpr e ++ ")"
...
| ’log e ->
"log(" ++ pprintExpr e ++ ")"
| ’log10 e -> "log10(" ++ pprintExpr e ++ ")"
| ’time -> "time"
| uk:<Real> -> mkvar uks expr
| val r:Real -> real2modelicaString r
Each case matches a certain form of expression. For example, we use the infix notation
of matching binary operators. For matching application to a function, we use the pattern
expression starting with an apostrophe. For example, the line:
| ’log e ->
"log(" ++ pprintExpr e ++ ")"
is equivalent to
| x e when x == log ->
"log(" ++ pprintExpr e ++ ")"
The line matching an unknown is calling a function mkvar which takes a data structure
representing all unknowns as its first formal parameter, and this particular unknown as
its second. All unknowns in the circuit have been given a unique integer value. Hence,
mkvar looks up the integer value for expr and prints out the string.
The rest of the source code in Appendix D.10 should be self explaining.
12.2.2 Simulating the DAE
The second example of using a model is to simulate the model using an external DAE
solver. However, the semantics for how to extract the equations, iterate over the simulation interval, store data, etc., is carried out in a MKL library. The standard library file
simulation.mkl in Appendix D.9 shows a listing of the source code.
The main simulation function is called simulate:
let simulate model:Equations -> steptime:Real -> endtime:Real ->
SimulationResult =
let (model2,probes) = elaborate model in
let probelist = Map.toList probes in
let ukmap = makeUkMap model2 in
let residual = makeResidual model2 ukmap in
let (yy,yp) = makeInitValues model2 ukmap in
let id = initConditionCorrection ukmap in
let state = DAESolver.make yy yp id residual in
let simloop currtime:Real -> acc:[StepVal] -> [StepVal] =
if currtime >=. endtime then acc
188
12 Implementation, Verification, and Evaluation
else
let stepval = makeStepVal currtime yy probelist ukmap in
let newtime = DAESolver.step steptime state in
if newtime == 0. then acc
else simloop (newtime +. steptime) (stepval::acc)
in
(makeProbeNames probelist 1,revResult (simloop 0. []) [])
This function takes as input a model, the step size, and the end time of the simulation.
First, it elaborates the model and gets a new model2 together with the probes mapping. The sixth line calls makeResidual for generating the residual function for the
DAE. The residual is a list of expressions, where each expression represents the difference between the left hand side and the right hand side of each equation. The residual
function is a callback function that is called when initiating the external solver, using
DAESolver.make. The residual function itself should have type
type Residual = Real -> {Real} -> {Real} -> [Real]
where the first argument is the current time, the second argument is a Real array with values for the unknowns, and the third an array with values for the differentiated unknowns.
The function that generates the residual is
let makeResidual model:Equations -> ukmap:UkMap ->
ctime:Real -> yy:{Real} -> yp:{Real} -> [Real] =
let realExpr e:<> -> Real =
match e with
| (val f:(Real -> Real -> Real)) e1 e2 ->
f (realExpr e1) (realExpr e2)
| (val f:(Real -> Real)) e1 -> f (realExpr e1)
| val v:Real -> v
| ’time -> ctime
| der x ->(match x with
| uk:Signal -> Array.get yp (fst (Map.find x ukmap))
| _ -> error "Derivatives only allowed on unknowns")
| uk:Signal -> Array.get yy (fst(Map.find e ukmap))
| _ -> error "Unsupported model construct"
in
let traverseEq m:Equations -> acc:[Real] -> [Real] =
match m with
| e1 ; e2 -> traverseEq e2 (traverseEq e1 acc)
| e1 = e2 -> (realExpr e1 -. realExpr e2) :: acc
| _ -> acc
in traverseEq model []
When creating the residual, the function makeResidual is partially applied to the equation system and an ukmap function. The rest of the function should be fairly straightforward.
For details, see the full source code listening in Appendix D.9.
189
12.3 Verification
Test
1
2
3
4
5
6
7
8
9
10
11
Name
SimpleCircuit
ComposedCircuitA
ComposedCircuitB
DriveLine
Gear
GearDamper
OneTorque
TwoTorques
SineInertiaDamper
LotkaVolterra
Mechsys120
Domain
Electrical
Electrical
Electrical
Mechanical
Mechanical
Mechanical
Mechanical
Mechanical
Mechanical
Plain DAE
Mechatronic
Method
S/T
S/T
S/T
S/T
S/T
S/T
S/T
S/T
S/T
S/T
T
MKL
Equations
23
18
18
42
30
45
16
20
40
6
1588
Modelica
Equations
46
37
42
53
41
57
21
32
48
3
2922
Table 12.1: Experimental results when modeling and simulating different systems
using the modeling kernel language compared to the Modelica tool Dymola. In the
column “method”: S = simulated with MKL, T = translated to flat Modelica from
MKL.
12.3 Verification
Different aspects and features of MKL have been discussed in previous chapters, but how
do we know that the semantics is correct? Actually, we shall first ask ourselves by what
we mean by correct semantics. Because the semantics of the language is the definition of
the language, in what aspect can it be correct or incorrect?
One aspect is the relation between the static semantics and the dynamic semantics,
i.e., to prove or justify type safety of the language. Even though this is a strong property,
it does not guarantee that programs and models behave as expected.
Another part of the semantics is the elaboration semantics with the connection semantics for elaborating acausal connections. In what way can we prove or justify that this
semantics is correct?
Our approach to justify the correctness of the semantics with regards to what a user
can expect of such asystem is to verify the system against a state of the art solution. We
have chosen to view the way of modeling in Modelica as the specification and then verify
that we can model the same model components in MKL and that they give the same
simulation results. This approach can be viewed as a high level system test, where we
tests the following aspects of the system
• The dynamic semantics for collapsing the instance hierarchy, i.e., that the semantics
for models and unknowns works as expected (semantics described in Chapter 10).
• The connection semantics for analyzing the equation system and generating connection equations (semantics described in Chapter 11).
Consider Table 12.1, which shows the tests that have been performed.
Tests are performed in the electrical domain, mechanical domain, and the combination, the mechatronic domain (see column three). A standard library for both the mechanical and the electrical domain has been created, where a portion of the continuous-time
190
12 Implementation, Verification, and Evaluation
model components of Modelica’s standard library components are modeled in MKL (see
Appendix D for a list of the model part of the library).
Column four of Table 12.1 titled method states how the verification was conducted.
The letter T stands for translation. Each such test follows this procedure:
1. The model is created in Modelica using standard components in Modelica standard
library. Sensor components are inserted into the model and connected for later
inspection.
2. The same model is created by using components from MKL’s standard library. This
library has been modeled according to the Modelica library. Sensor components are
inserted into the model in the same way as in the Modelica model.
3. The Modelica model is simulated using Dymola 6 [45]. Data from the sensors are
plotted and visualized. The number of equations after elaboration were read out
from the translation log and added to column 6 of Table 12.1.
4. The MKL model was translated and exported to a flat Modelica file using the MKL
transformation code in Appendix D.10. The number of equations is counted and
the result value is given in column 5 in Table 12.11 .
5. The flat Modelica file generated in the previous step is simulated using Dymola 6.
The sensor variables are plotted and visualized.
6. The plotted results from the Modelica model and the translated Modelica model are
visually compared.
These tests have verified the elaboration semantics and the capabilities for intensional
analysis of models. Tests also marked with the letter S which stands for simultation also
verifies the MKL simulation implementation. For the simulation verification, the first
three steps of the above were performed. This was followed by the following steps:
1. The MKL model is simulated using the MKL library simulation.mkl, which
is listed in Appendix D.9. The underlying numerical DAE solver is IDA from the
SUNDIALS solver suite [68]. The result of the sensor variables is plotted using
GNU Plot v3.8h.
2. The plotted result from the MKL and the Modelica simulations were compared.
All tests, except test 11, are performed using both MKL simulation and translation to
Modelica. In case 11, the IDA SUNDIALS solver could not find a consistent initial
solution. Because we have not implemented Pantelides algorithm [118] for index reduction, and the IDA Sundials solver can find consistent initial conditions for so-called
semi-explicit index-one problems [68], we believe that test 1 is a higher-index problem.
However, the test with translation gave the same simulation result.
1 The equation count includes equations for sensors and probes. This is the reason that the number can
mismatch compared to other counting of equations stated earlier in this thesis. Note also the exceptional test
case 10, where MKL has more equations than in Modelica. The reason is that probes give extra unknowns and
thus also equations. These equations for probes is also the reason why the model becomes a DAE instead of an
ODE.
12.4 Discussion and Evaluation
191
12.4 Discussion and Evaluation
In the following subsections we will discuss and evaluate the MKL approach according
to the following aspects introduced in Section 1.3:
• Safety Aspects
• Expressiveness and Extensibility Aspects
We will also briefly discuss performance aspects regarding the current prototype implementation.
12.4.1 Safety Aspects
In the problem area discussion, we described three main challenges regarding error handling:
• Detecting the existence of an error early.
• Isolating the fault implied by the error.
• Guaranteeing that the faults do not exist.
Because MKL is a language for defining EOO construct using defining standard libraries,
error detection and fault isolation can be considered from several different perspectives.
System Modeling Errors
System modeling errors can be introduced by the modeler by entering wrong or illegal
equations. The type system of MKL can detect and isolate certain kinds of errors, such
that nodes from different domains do not mismatch. We regard this early static checking
and fault isolation as very beneficial from a modeling perspective, compared to if the
language would have been dynamically typed. The static checking in this regards can be
seen as similar to the one in Modelica, but the difference is that in MKL new language
constructs (consider e.g., probes or initial values) in almost all cases can be added to the
language using libraries. Even these new constructs will be type checked at compile time.
However, several modeling errors will still not be detected by the type checker, e.g.
constraint errors or physical unit of measurements errors. We have in earlier work studied both of these properties in the context of Modelica, but not yet for MKL, i.e., the
constraint delta approach is not yet adapted and implemented for MKL. However, initial
observations have been made that the constraint delta approach could be made much simpler by using MKL’s connect semantics. Consider the following model of an inductor,
where we have printed out the constraint delta value for each part:
let Inductor L:Real -> p:Electrical -> n:Electrical -> Equations =
let i:Current in
C∆ =-1
let v:Voltage in
C∆ =-1
ElectricalBranch i v p n;
C∆ =1
L *. (der i) = v
C∆ =1
192
12 Implementation, Verification, and Evaluation
The constraint delta value for specific unknowns, here the current i, and the voltage v
obviously have C∆ = −1. Recall from Section 11.2.2, that for each branch, in this case
an ElectricalBranch, rule 3 states that a potential equation should be added for that
branch. Hence, a branch (both the binary and the reference branch) always has C∆ = 1.
The last line shows an ordinary equation, which unsurprisingly has C∆ = 1. Hence, we
can directly see that the model is balanced.
What about the other unknowns and equations that are generated during elaboration?
There are two cases. Rule 1 states that an unknown potential should be added for each
node in the model. Rule 2 states that a sum-to-zero equation should be added to each
node in the model. Hence, these two rules always cancel out each other and their delta
contribution is zero.
We believe that this approach is simpler and more intuitive to understand than using
Modelica’s connection semantics (compare with the constraint delta algorithm described
in Chapter 6). However, we leave as future work to incorporate this into MKL’s type
system.
Language Design and Specification Errors
We have in this work formally specified the core of the MKL language. This could be
regarded as beneficial in the sense that it becomes less ambiguous and open for interpretation. However, extending such a specification is not trivial and would affect an implementation substantially. Our approach therefore tries to move the semantic extensions of
the language into libraries, so that the core can be untouched. Compared to, e.g., Modelica and VHDL-AMS, these languages can grow by adding new modeling abstractions
without changing the semantics of the language. However, to extend how the models
can be used typically needs language extensions. In the Modelica case, this is often accomplished by adding new annotations and then informally describing the meaning of
these annotations in the language specification. In contrary, in the MKL approach, these
extensions are described in libraries. Hence, we avoid the problem of language and specification errors by not introducing this kind of new construct in the language. However,
the question is if the language is expressive enough, so that these semantic extensions can
be described in libraries. We will discuss expressiveness aspects in the next section.
Tool Implementation Errors
If a language is implemented and used by just one software tool/compiler, there is a risk
that the implementation becomes the reference implementation describing the language.
However, if several tools exist that should be able to use models created by other tools, it
is vital that they treat the models in the same way. In MKL we have the same challenge as
for other languages that the implementation must follow the specification. We have tried
to mitigate this problem by formally specifying the core of the language using operational
semantics. However, the main contributing idea in MKL is that the semantics for how to
use models is not part of the language. Instead, by implementing the simulation and
translation steps in a library, we get an executable specification that can be shared directly
by different tool vendors.
12.4 Discussion and Evaluation
193
12.4.2 Expressiveness and Extensibility Aspects
We will now discuss how well MKL solves the problem of expressiveness and extensibility of an EOO language.
Expressiveness of Modeling Constructs
Evaluating the expressiveness of a programming language is a subjective task. If the
languages that should be compared are Turing complete, they can all be used to solve the
same problem. In such a case the expressiveness of the language states how “easy” it is
to express a certain task. For example, if we consider the continuous-time aspect of an
EOO languages where the problem can be specified as a DAE system of equations, the
expressiveness power of the system would mean how “easy” it is to model a system.
In Chapter 8, we introduced the idea of higher-order acausal models, and showed that
in the MKL setting we use ordinary higher-order functions to define the models. We
showed how this could be used to parameterize models with other models, how a model
can create new models, and how models could be recursively defined. In Modelica, several of these modeling tasks can be performed with for-equations (expressing repeating
connections), model redeclare (parameterizing a model with another model) and conditional components for selecting if a model instance should exist or not. Comparing these
language constructs with HOAMs regarding expressiveness is like comparing apples and
oranges, i.e., it is subjective to personal preferences and tastes. However, we argue that
HOAMs can model most of these special constructs in one uniform way. Hence, this
enables simpler and more concisely specified language specifications.
Expressiveness of Translation Constructs
It is a well known fact that statically typed languages can reduce the expressiveness of
a language. For example, in the current version of MKL, we do not support parametric
polymorphism. Hence, we need to write several similar functions, e.g., a new fold
function for each type it can operate on. This is a limitation in the current MKL language.
An extension to support parametric polymorphism is planned as future work.
In contrast, in a language where the type checking is performed at runtime, we gain
expressiveness/flexibility, but loose the property of compile time checking and early error
feedback.
Our design where a model can be of either a specific type, e.g. <Int>, or a model
of any type <> is an attempt to find a good trade-off. As we discussed earlier, the specific model type is used to check the correctness of models during modeling. However,
by relaxing type equality checks to a consistency check where for example <> is consistent with <Int>, we get an expressive semantics for traversing and inspecting models.
However, the expressiveness comes at a price. For example,
let v1 = ((val(+)) (val 3)) (val 10)
defines an a model where the prefix variant of the plus operator is applied to two integer
models. The match expression
let v2 = match v1 with
| x y -> x false
194
12 Implementation, Verification, and Evaluation
matches the model and extracts x, which is (val(+))@(val 3), where the model
application has been written out explicitly with infix operator @. However, x has now type
<> because the static type checker cannot know what specific model type the left term of
the model has. Hence, x false creates a valid expression (val(+))@(val 3)@
(val false). This transformation can be regarded as nonsense, but is still legal from
a type checking point of view. Now, let us define a function foo for deconstructing v1
and v2:
let foo v:<> -> String =
match v with
| x + (val y:Int) -> int2string y
| _ -> "Not an Int"
Parameter v is of any model type. If we apply foo to v1, we get as result "10", using
the first mathch case because we match that the value type is an Int. However, if we
apply foo to v2, we get as result Not an Int. Hence, even if we can create bogus
model terms during transformation, we cannot extract using pattern matching terms that
violate the types, i.e., int2string cannot in this case accidentally get a boolean value
as an argument. We should again note that this is our believed type safety of the system,
it is not yet proven.
From our preliminary tests of implementing both elaboration semantics, code generation and export of flat Modelica, as well as simulation code, we have found that the static
checking has helped us to find many bugs in the programs. The risk of creating bogus
transformations, as the one above, has surprisingly not been a problem so far. However,
our tests are as yet far too small and limited to draw any general conclusions in this matter.
Extensibility
Extensibility of a language concerns how easy it is to add new language constructs to
the language. If the language has a large, complex, and informal language specification, it might be hard to predict the consequences of adding a particular language feature.
Moreover, if there exist several different compiler/simulation tools implemented for the
language, new language constructs can give major consequences for each implementation.
In Chapter 4 we argued that the most preferable way to grow a language (to extend
it) is growth by new user defined abstractions, i.e., that the language is not changed at
all. In for example Modelica or VHDL-AMS, this is accomplished for the modeling
part by enabling a library developer to create new libraries in different physical domains.
However, in the Modelica case, it has turned out that several new language constructs
need to be added at each language revision (every 1-2 year). These changes are needed to
enable better support for new model libraries. Moreover, the actual use commands, e.g.,
simulation, checking, etc., of the models cannot be specified by the user, these are defined
in the implementation of the used software tool.
In contrast to Modelica, our approach emphasizes the use of new user defined abstractions even for how the model is used. For example, if the language has support for
specifying initial values to variables, and later it is decided by the language design committee that a library also needs initial equations, the definition of MKL does not need to
be changed. For example, by adding the following two lines
12.4 Discussion and Evaluation
195
Figure 12.2: Elaboration time in relation to the number of generated equations.
let InitEquation : <Real -> Real -> Eqs>
let (=.) : <Real -> Real -> Eqs> = InitEquation
we have defined a way to specify initial equations using the infix operator =. Of course,
the actual semantics for how to handle these equations must be specified by elaboration
functions, but this can be done in a library instead of in a software tool such as a model
compiler. We see the following main benefits with this approach
• Tool vendors do not need to update their product for each library extension
• Library developers becomes less dependent on tool vendors, i.e, they can extend
the language themselves
• The likelihood that a model will behave the same way in different tools increase.
We believe that the examples and implementation of this thesis work give the evidence
that this is indeed possible.
12.4.3 Performance Aspects
Performance of simulations, i.e., the time it takes to simulate a model, is important. In
this thesis we have implemented an interpreter for evaluation and verification of our solution. However, we argue that performing a performance comparison between our current
interpreted implementation with available Modelica implementations would be subject to
196
12 Implementation, Verification, and Evaluation
bias. Firstly, we do not know if the Modelica implementations are flattening, sorting equations, and also performing other kinds of symbolic manipulation. On the other hand, our
solution is interpreted, while for example both Dymola and OpenModelica are running
compiled code for the elaboration phase. Also, keep in mind that the comparison is for
different EOO languages, MKL in our case and Modelica for Dymola and OpenModelica.
However, a performance aspect that is interesting regardless if the solution is interpreted or compiled, is how well it scales. In this case, we are interested in how the elapsed
simulation time increases with respect to the size of the model. The size of a model can be
measured in different ways, e.g., number of submodels, number of branches etc. We have
chosen to use the number of equations generated after elaboration as the measurement of
size. The rationale for this choice is that we can compare models with different structure
and domains.
We have performed experiments with two different models. The first model, called
MechSys is the model with a flexible shaft that was presented in previous chapters. The
parameter that has been changed to get different measurements is the number of elements
in the shaft. For example, in the largest test case 40000 elements of the shaft generated
520026 equations. The test model for MechSys is listed in Appendix D.11.
In the second experiment called CircuitHierarchy, a model consisting of three
electrical components was created. This model was then instantiated to three new components, which were connected. This procedure were performed recursively, generating
442873 equations for 11 levels. The test model for CircuitHierarchy is listed in
Appendix D.11.2.
Consider now Figure 12.2 that shows the elapsed simulation time in relation to the
number of generated equations for the two models described above.
The CircuitHierarchy has a few measurement points with larger equations sizes.
The reason is that 10 hierarchy levels generate 147628 equations and 11 levels generate
442873 equations. For larger equation sizes the underlying OCaml runtime system generates an error.
Two obvious observations can be made from the graph. Both cases grow approximately with the same factor and the growth is not entirely linear. However, when considering that half a million equations is many equations if it would have been a model used
in practice, we would argue that the solution in these cases can be considered scalable.
However, we shall also notice that the elaboration phase is a minor source of the total
simulation time, compared to symbolic manipulation and numerical simulation. Hence, it
is premature to draw too many conclusions from these tests.
12.5
Chapter Summary and Conclusions
We have in this chapter given an overview of the prototype implementation of MKL as
well as shown examples of two ways of using models: for continuous-time simulation
and exporting Modelica code.
We explain how the prototype has been verified by simulating several example models
using both MKL and a Modelica environment. Finally, we discuss and briefly evaluate
our solution from a safety perspective, expressiveness and extensibility perspective, and
performance perspective.
12.5 Chapter Summary and Conclusions
197
We can conclude that our approach gives similar possibilities of continuous-time modeling as a state-of-the-art modeling language Modelica. However, MKL does not yet
support hybrid modeling and it is therefore hard to compared larger models from e.g.,
Modelica Standard Library (MSL). The main difference of MKL and languages such as
Modelica is the ability in our approach to not only create reusable modeling libraries, but
also to create libraries for inspecting, translating, and using models.
198
12 Implementation, Verification, and Evaluation
Part III
Related Work and Concluding
Remarks
199
13
Related Work
I
this chapter we discuss the most closely related work. The chapter is structured as
follows:
N
• We first give a short overview of the most prominent equation-based modeling languages available. We then discuss how MKL is related to these languages (Chapter 13.1).
• We discuss related work related to Modelica semantics (Chapter 13.2), as well as
MKL semantics (Section 13.3).
13.1 Equation-Based Modeling Languages
In this section, we discuss and describe different equation-based modeling languages primarily used for physical modeling. For some of the languages we also directly compare
to MKL. At the end of the section, we summarize the main differences and similarities
between our approach and the discussed languages.
13.1.1 Modelica and Predecessors
Modelica is an equation-based object-oriented (EOO) language designed for modeling
large and complex physical systems [104]. For a brief overview of the language, see
Chapter 2.
The design of the language is an international effort to create a unified object-oriented
language for system modeling and simulation [55]. Language designers of a number
different equation-based modeling languages have actively participated in the design of
Modelica [51]. We now briefly present some of the predecessor languages.
201
202
13
Related Work
The language Dymola (Dynamic Modeling Language) was introduced by Elmqvist in
1978 [47]. It introduced concepts for facilitating creation of large models by hierarchical
composition of sub-models. Dymola stands today for Dynamic Modeling Laboratory and
is a commercial product based on the Modelica environment [45].
The Omola language by Andersson [6] is an object-oriented acausal modeling language that makes use of several concepts from OOP, including the class concept and
inheritance. The language handles both discrete and continuous-time systems.
Another early language for object-oriented acausal modeling is the Natural Model
Format (NMF). This language was first developed and introduced for building simulations [128].
Yet another language is SIDOPS+ [16] that supports block-diagram and bond graph
models. It was intended as a open language that focused on modeling of mechatronic
systems.
Smile is a simulation environment developed for energy systems that is based on
object-orientation and equation-based modeling principles [82]. A variant of the Smile
system called Smile/M is extended with the capability to also compile Modelica models [50]. The Smile system separates the modeling language from the experimental description language. The modeling language is an extension of Objective C [50].
ObjectMath is an extension of Mathematica for equation-based, object-oriented modeling [58]. The language combines object-oriented, constructs such as classes and inheritance, with the computer algebra facilities of Mathematica.
13.1.2 Extensions to Modelica
There are also a number of languages defined as extensions to the Modelica language.
MOSILAB is a modeling and simulation tool for modeling of structurally dynamic
systems [112]. It is implemented as an extension to the Modelica language adding statecharts for modeling discrete model switches.
Optimica is an extension to Modelica for compact formulation of both static and dynamic optimization problems [5, 79]. A key aspect of the extension is that the formulation
of the optimization problem is independent of the numerical algorithm that is used for
solving the optimization problem.
Both of these extensions show the need for extensibility of an EOO language. Also,
Optimica is an example where Modelica models are used for other purposes than simulation.
13.1.3 VHDL-AMS
VHDL-AMS is a hardware description language (HDL) used for describing digital, analog, and mixed-signal systems [10]. It is an extension to VHDL also supporting analog
signals; i.e., continuous-time models. It is an ISO standard [72].
A VHDL-AMS model is defined by an entity and one or more architectures. The
entity is the interface of the model and the architecture its implementation. In Modelica,
the class type specifies the interface and the model itself is the implementation. Similarly,
in MKL, the type of the function abstracting the equation system is the interface, while
the body of the function containing equations is the implementation.
13.1 Equation-Based Modeling Languages
203
In VHDL-AMS, quantities represent the unknown variables in a DAE [40]. The language supports three kinds of quantities: free, branch, and source quantities. A free
quantity is a signal that can be used for causal modeling. A branch quantity is used for
modeling conservative energy systems, i.e., acausal modeling. A source quantity is for
modeling of frequency and noise. The free quantity is similar to MKL’s standard library’s
definition of Signal. In VHDL-AMS, terminals are created by a specific nature, e.g.,
the electrical nature. These terminals are then connected to ports of entities. Terminals and MKL nodes are similar and connecting to a port is basically the same as passing
a node to a model function in MKL.
Branch quantities can be declared inside architecture bodies. Branch quantities are
used for defining across and through quantities (same as potential and flow variables in
Modelica). This has a direct correspondence to branches as defined in MKL. In fact, the
naming and idea of branches is inspired by VHDL-AMS.
13.1.4 Verilog-AMS
Verilog-AMS is a hardware description language (HDL) that is an extension to Verilog
with analog and mixed-signals [3]. In Verilog-AMS, signals are associated with nodes,
which are connected to ports of components. Also, models of conservative energy systems
have potential and flow values associated with each node. In Verilog-AMS, branches
are the paths between two nodes through a component. Each branch has the potential
difference and the flow. Hence, the basic structure for defining branches, nodes, flow
etc. is similar between MKL’s standard libraries and Verilog-AMS. However, an essential
difference is that the MKL language itself does not include these constructs, while they
are part of the Verilog-AMS language.
13.1.5 gPROMS
gPROMS is an equation-based language used for combined lumped and distributed parameter processes. It was introduced in 1992 by Barton [13] in his PhD thesis and has
evolved to become a commercial product. Its main application domain is chemical process
modeling. The language is based on three kinds of entities: models, tasks, and processes.
The model describes the continuous-time behavior of the modeled system, including discrete changes. Tasks describe the disturbance and external actions on the system. The
process describes the complete simulation experiment. The language has later been extended by Oh and Pantelides to support mixed integral, partial differential, and algebraic
equations (IPDAEs) [115].
13.1.6 Hybrid Chi
Hybrid χ (Chi) [59, 146] is a hybrid specification formalism that can describe discreteevent, continuous-time, and hybrid systems. The language is a concurrent language based
on Communicating Sequential Processes (CSP) (the discrete-event part), and differential
algebraic equations (DAEs) (the continuous-time part). The language does not yet support acausal connections. Its syntax and semantics has been formalized using structured
operational semantics [146, 145].
204
13
Related Work
13.1.7 Functional Hybrid Modeling and Hydra
Functional Hybrid Modeling (FHM) is a paradigm that combines functional programming
and non-causal (acausal) hybrid modeling [109, 110]. The concept of Functional Hybrid
Modeling (FHM) is a generalization of Functional Reactive Programming (FRP) [150],
which is based on reactive programming with causal hybrid modeling capabilities. Both
FHM and FRP are based on signals that conceptually are functions over time. Unlike FRP,
which only supports causal modeling, the aim of FHM is to support acausal modeling with
structurally dynamic systems.
The most developed language within the FHM paradigm is Hydra, which is created
by Giorgidze and Nilsson during recent years [61, 62, 63]. However, the basic ideas for
the language were sketched already in 2003 by Nilsson et. al. [109].
Similar to MKL Hydra is supporting continuous-time modeling using DAEs. Both
languages are supporting a kind of model abstraction that is first-class, called signal relations in Hydra. Signals in FHM are time-varying values, i.e., a function from time to a
value.
In FHM/Hydra, there are two distinct levels: the functional level and the signal level.
The former deals with time-invariant expressions, e.g., signal-relations and the latter with
time-varying quantities, e.g., signals. Signal relations and signal relation applications are
used for composing equation systems. That is, in FHM, there is a separation between
function application at the functional level and signal relation application at the signal
level. In contrast to FHM, MKL uses function abstraction and function application both
for unknowns (representing signals during simulation) and for constant values.
Hydra is implemented as an embedded DSL using Haskell with the Glasgow Haskell
Compiler (GHC) extensions as the host language [63]. It is designed to support structural
dynamic systems where the numerical simulation result is computed using the SUNDIALS solver suite [68] and the residual function is just-in-time (JIT) compiled using LLVM
[86]. It is using a mixed-level embedded approach, combining both shallow embedding
(domain-specific syntax is expressed directly in the host language) and deep embedding
(making use of interpretation and compilation). We shall also note that embedding is an
implementation technique for Hydra that is not required by the FHM paradigm.
Currently, there does not exist any published formal semantics for Hydra or FHM,
besides the formalization available for the host language (Haskell). However, the formalization of the semantics has been one of the main objectives for MKL.
13.1.8 Sol
Sol is a equation-based modeling language designed for modeling and simulation [154].
Its design is based on Modelica, but the objective of Sol is be a minimal research language
for simulating variable-structure systems. In his PhD Thesis, Zimmer [155] develops a
methodology for dynamic processing of differential-algebraic equation for arbitrary structural changes of the equation systems. The Sol language is used to test and evaluate the
methodology within several different domains.
13.2 Modelica Semantics
205
13.1.9 Acumen
A recently developed modeling language called Acumen [153] is aimed for bridging the
gap between analytical models and simulation code. It supports continuous-time modeling of PDEs, discrete-time modeling using event-driven functional reactive programming
(E-FRP), and hybrid models. It has so far been evaluated in the mechanical domain.
13.1.10 Comparison to MKL
Similarly to all of the above mentioned languages, MKL can be used for continuoustime modeling and simulation using DAEs. However, we have not yet evaluated the
approach for hybrid systems. Compared to Sol and FHM, which both have been designed
for structurally dynamic systems, MKL has not yet been extended with such language
feature. However, as stated in the future work (Section 14.2), we believe that MKL can
be a good platform for experimenting with structurally dynamic systems.
According to Definition 8.2.1 on page 115 FHM/Hydra and MKL are the only ones
of the above mentioned languages that have full support for higher-order acausal models.
Modelica has a construct called redeclare that can parameterize models with other
models, but models cannot be passed to or created by functions.
In contrast to all the above languages, the semantics of how to use the models can
also be specified in MKL libraries. This enables extensible formal executable specifications where important language features are expressed through libraries rather than by
adding completely new language constructs. For example, probes (Section 11.3), export
of equation systems (Section 12.2.1), and simulation (Section 12.2.2), are all constructs
implemented as MKL libraries.
We have formally defined both the static and dynamic semantics for a core part of the
MKL language as well as proven type safety for the core language. This formalization
includes both phase 1 (type checking) and phase 2 (collapsing the instance hierarchy)
of the elaboration process (recall Section 11.1 on page 159). Moreover, because phase
3 (the connection semantics) is specified as an executable library within MKL, we have
formalized most of the elaboration semantics1 .
13.2 Modelica Semantics
In this section we discuss some related work regarding Modelica semantics. First, we
state previous work on specifying the elaboration semantics. Second, we discuss related
work on types and isolating faults in models.
13.2.1 Natural Semantics
Already in 1998 Kågedal and Fritzson [84, 85] defined a formal specification for a subset of the Modelica language. It was a Natural Semantics [81] specification expressed
in the executable specification language Relational Meta-Language (RML) [120]. This
work influenced the design of the language and the official Modelica specification. The
1 Since we in this thesis have not formalized translation steps e.g., pattern compilation and other constructs,
e.g., lists and tuples, we do not want to claim that the whole process has been formalized.
206
13
Related Work
executable specification has gradually evolved and is now the code base for the OpenModelica project [117]. In 2006, the code base was automatically translated from RML
to Meta-Modelica [56] with the purpose of making it more accessible to software engineers in the Modelica community. Hence, today the project is more intended to be a
complete implementation of the language than a specification itself.
13.2.2 Instance Creation
Mauss has made several contributions towards formally describing the elaboration process
(called instance creation in his work) of a subset of Modelica, i.e., the translation process
from a Modelica model into a system of equations [95]. His published work describes an
algorithmic specification approach that focuses on Modelica’s complex look-up rules and
modification semantics, including redeclaration of classes and components. Semantics
for describing restrictions on validity of a model, such as types, restricted classes, and
most prefixes are not considered.
13.2.3 Modelica Types
To the best of our knowledge our work on the type concept in Modelica is the first study
to introduce and differentiate between class types and object types. An overview of the
type concept was given by Fritzson [51, Section 3.14] in 2004, but it did not include the
insights about class types and object types that are discussed in this thesis.
13.2.4 Balanced Models
In September 2007, a new version 3.0 of the Modelica specification was released [103].
The largest change in the language was the new constraint that all models in the Modelica
language must be locally balanced, meaning that the number of unknowns and equations
must be equal at every hierarchical level of a model [116]. The exception is for partial
models, which are not checked. Enforcing local balancing of models is basically the
same as stating that constraint delta and effect delta (see Chapter 6) should be zero in
all connectors and models. However, even if the approaches are similar, there are some
distinct differences.
The balanced model concept in the Modelica specification has taken a "top-down"
approach and defines its solution for the whole Modelica language. The constraint delta
approach is given for a small subset of the Modelica language, with the purpose of stating
a detailed algorithm.
The Modelica specification requires that models are always balanced, with the exception of partial classes. The constraint delta concept as explained in Chapter 6 is more
flexible, and accepts that sub-components are over or under-determined, as long as the
global model has a constraint delta of zero. Both of these approaches are justified by
examples and tests.
It should also be noted that the idea of using these approaches were developed in
parallel within Dynasim and by the author during year 2006. At the time of the publication
of the constraint delta approach [28], the paper handed out and discussed at the Modelica
Association design meeting. During the late 2006 and early 2007, further interaction and
13.3 MKL Semantics
207
discussions have occurred between the author of this thesis, Dynasim, and members of
the Modelica Association.
Finally, it should also be noted that there is a paper by Nilsson et. al. [109] from
2003, where the idea to incorporate information about the balance between equations and
unknowns into the type system is stated. However, no information or strategy on how this
should be conducted is presented.
13.2.5 Structural Checking of Models
There has been a number of attempts to perform more sophisticated analysis for detecting
and isolating constraint errors. Instead of just counting equations and unknowns, these
methods try to determinate if the system of equations is structurally singular, and in such
a case isolate the fault.
An early attempt of semiautomatic debugging technique was suggested by Bunus
& Fritzson [29]. They implemented a system called AMOEBA (Automatic Modelica
Equation-Based Analyzer), which performs a graph algorithm on the flat system of equations. The source of the error is then traced back to the original component. Hence, this
approach can detect faults that goes undetermined by the constraint delta approach (the
system is singular but the number of equations and unknowns match). However, in the
case of an illegal number of equations and variables, the simple counting approach is
sufficient.
Nilsson [108] outlines an approach to perform check of structurally singular systems
at the type level. The idea is similar to our work on the structural constraint delta, but
instead of just annotating each type with a single integer value, Nilsson suggests to expose
information about which variable that appears in which equation. However, to not make
the type as large as the whole system of equations, Nilsson suggest a way to approximate
the structural information for the types.
13.3 MKL Semantics
In this section we first discuss types and dynamic semantics related to the formalization of
semantics of MKL. This is followed by discussion about related techniques for metaprogramming.
13.3.1 Formal Semantics
The formalization of the dynamic semantics of the core of MKL (Chapter 10) is given
using small-step semantics. An alternative would be to use big-step semantics, also called
natural semantics [81]. We choose the small-step style because of the possibility to use
the progress and preservation lemmas for proving type safety [124].
The embedding of values in model value expressions val e : τ and the use of the any
model type <> is inspired by the work of Abadi et. al. [1] about dynamic typing in a
statically typed language. In their work they provide a language construct called dynamic
that is packaging a value together with its type. Such an term has the type Dynamic
(note the capital letter) that can later be deconstructed using a typecase construct. A type
208
13
Related Work
system using gradual typing allows both static and dynamic type checking in a single
programming language [132, 133]. A type consistency relation is used instead of type
equality. We have adopted a similar approach using type consistency, where the any
model types <> is consistent with specific model types <τ > for some type τ . The main
difference compared to MKL’s type system is that in gradual typing any type is consistent
with the dynamic type (denoted ?), but in MKL only model types can be consistent with
<>.
The concept of generalized algebraic data types (GADTs) is a powerful generalization of algebraic data types that is part of languages such as Haskell, Standard ML, and
OCaml [123]. GADTs have in the literature appeared under different names, such as
guarded recursive data types [152], equality-quantified types [131], and first-class phantom types [39]. GADTs can for example be used when embedding DSLs in a host language (e.g., Haskell) and then check if a program in the DSL is well-typed. This has some
similarity to MKL’s approach to type checking with specific model types. Potentially an
approach where GADTs are used in MKL’s type system could preserve type information
of specific model types during transformation of models. However, it is not clear whether
incorporating GADTs would preserve the expressiveness of the current MKL approach,
or how the concepts of unknowns and model lifting would be incorporated. We regard
this as interesting future research.
Lava is tool for specifying, designing, and implementing hardware [15]. Its language
is an HDL embedded into Haskell. Similarly to MKL, Lava is using higher-order functions to compose circuits together. However, Lava is designed for digital circuits and is not
concerned with the connection semantics appearing in acausal languages. Claessen [41]
describes two approaches for solving the problem in a lazy language that circuits are
graphs but viewing them using algebraic data types makes it not possible to distinguish
them from infinite trees. He both suggests an approach using monads [149] and an approach called observable sharing. The latter makes the graph sharing observable by extending the language with non updateable reference cells and an equality test for sharing
detection. Because MKL is a call-by-value language we have taken a less sophisticated
approach using the ν(τ ) expression to generate new unknowns that can be used to represent nodes in a circuit. These nodes can then be directly compared using an equality
operator.
Instead of using the λ-calculus as the basic calculus for MKL, the pattern calculus
by Jay [77] could be an alternative. It is an expressive calculus where patterns are part
of the core calculus. However, we have in this thesis taken a more traditional approach
and formulated our language as an extension to the lambda calculus. Hence, the pattern
matching operations are not part of the core language but instead defined as a translation
to the the core language.
13.3.2 Metaprogramming in EOO Context
Most Modelica tools support some kind of scripting facility that can be used to programmatically start simulations and collect results. In the Dymola and OpenModelica cases
the script language is a subset of Modelica. Some tools also opens up APIs for inspecting
and traversing the abstract syntax tree of a model.
A limited form of metaprogramming facility for OpenModelica was presented in [9],
13.3 MKL Semantics
209
and followed up by the work of Fritzson et.al. in 2005 [56], where the Modelica language was extended with pattern-matching operations and transformations on ASTs. The
current language, called MetaModelica, is a heterogeneous metalanguage, meaning that
the metaprogramming language and the object language are not the same. In [127] Pop
shows how MetaModelica is used as the implementation language of OpenModelica.
In contrast to MetaModelica MKL is a homogeneous metaprogramming language in
the sense that it can create models and inspect the models in the same language.
13.3.3 Metaprogramming in General Purpose Languages
During the last two decades, there has been extensive research in the area of statically
typed languages aimed at extensional metaprogramming, for example MetaML [140,
143, 144] and its dialects (e.g., MetaOCaml [142]). In these so called multi-stage languages code can be created, combined, and executed.
MKL is not performing intensional analysis on the program code, but on the values of
a model type. Because models are treated as data and cannot be executed, the typing gets
much easier. Hence, we call our approach intensional analysis on models.
Static metaprograms are metaprograms that execute before the load time of the program or code that it manipulates [43]. A popular way of compile time metaprogramming
is to make use of the template system of C++. Hence, programs can be generated before
execution. Template Haskell [130] is another example of compile time metaprogramming. MKL does not support any compile time metaprogramming. During compile time,
expressions are lifted to be models, so that they can later be inspected.
210
13
Related Work
14
Concluding Remarks
I
the following final chapter, we state the conclusions (Section 14.1), and outline future
work (Section 14.2).
N
14.1 Conclusions
This thesis concerns the problem of designing and defining semantics of equation-based
object-oriented (EOO) modeling languages. We have studied this problem area in two
contexts, corresponding to Part I and Part II of the thesis. In the first part, we study
the state-of-the-art EOO language Modelica both by discussing the current language’s
properties, and proposing new language solutions. In the second part, we present a new
research language called the modeling kernel language (MKL). In MKL, reusable acausal
models, based on differential algebraic equations, can in a way analogous to what is done
Modelica be defined in model libraries. In contrast to Modelica, the semantics of how to
use the models, i.e., operations on models, are also defined in MKL libraries, and not in
language specifications or separate software tools.
The problem area of designing and defining the semantics of an EOO-language concerns trade-offs between several aspects of the language. We have focused on the tradeoffs between safety, expressiveness, and extensibility. We have studied these aspects
within three research areas:
• Understanding the semantics of the Modelica language
• Early detection of modeling errors
• Expressive and extensible formal semantics
211
212
14 Concluding Remarks
14.1.1 Understanding the Semantics of the Modelica Language
Studying the semantics of Modelica is interesting and important per se. The language is
the state-of-the-art EOO language today and widely used both in academia and in industry.
However, the language is large and very complex with an informal language specification.
Hence, the semantics of the Modelica specification is hard to interpret unambiguously. We
have discussed and analyzed two research questions concerning this area.
The first question concerns if there is a way to restructure an existing large informal
specification so that it becomes less ambiguous and still understandable for a general
audience. We discuss different alternatives and propose a middle-way approach for Modelica, where the grammar for ASTs shall be formally defined and the translation between
AST variants is informally described. Moreover, we discuss different ways of growing an
EOO language in general and Modelica in particular. The conclusion is that the objective
should be to design the language so that it can grow by allowing the user to define new
abstractions in the language, and in such a way make the language more extensible.
The second research question concerns the meaning/semantics of types in Modelica
and how it relates to the language’s concept of classes. We have analyzed the type concept,
which was only indirectly described in the Modelica language specification at that time.
The conclusion and also the main contribution of this work was the insight that Modelica
has two categories of types: class types and object types. The reason is that Modelica
has a structural type system making types and classes separate concepts. We explain the
findings by giving several examples, as well as defining a concrete syntax for specifying
the types. It was also concluded that Modelica’s prefixes are part of the types and a
categorization of an interpretation of the specification was proposed.
14.1.2 Early Detection of Modeling Errors
The third research question concerns the problem of determining if a model is over- or
under-constrained before elaborating a model. It is trivial to detect how many equations
and unknowns you have after elaboration. However, if the numbers do not match, it is
non-trivial to isolate the fault and give good user feedback for where the error is located
in the model.
We propose a novel concept that we call structural constraint delta. The basic idea
is simple; each type is annotated with an integer value stating the difference between the
number of equations and the number of unknowns of a model’s type. An algorithm is
detailed for computing the constraint delta value, which turns out to be fairly complex
mainly due to the connection semantics of the Modelica language. We successfully tested
the solution on a small subset of Modelica, but from that evaluation it is hard to give any
guarantees of correctness for a full Modelica implementation.
The work on structural constraint delta was first published in 2006 [28] and later
somewhat influenced the concept of balanced models for Modelica 3.0, released in 2007.
In retrospect, with the acceptance of introducing this non-backwards compatible change
to the Modelica language, we conclude that the idea of determining over- and underconstrained systems by considering the balancing of models is applicable in practice.
We would also like to emphasize that the idea of structural constraint delta is not limited to Modelica, and ought to be useful for EOO languages in general. In Section 12.4.1,
14.1 Conclusions
213
we briefly discussed how it can be used in MKL. The introduction of constraint delta
into MKL’s type system is considered future work, but preliminary investigation shows
that the method for computing the value seems simpler in the case of MKL’s connection
semantics than for Modelica.
14.1.3 Expressive and Extensible Formal Semantics
From the earlier study of Modelica, we have concluded that it is hard to formalize such
a large and complex language. Our study of Modelica can be viewed as a top-down
approach, trying to analyze something that is large and exists. Our next research question
concerns the opposite - a bottom-up approach to the design problem.
The fourth question for this thesis concerns the possibility to formally define an EOO
language, base it on the proved theory of the simply typed lambda calculus, and achieve
the same expressive power as state-of-the-art EOO languages. The result of our work
in this area is the first version of our research language MKL. MKL is fundamentally a
statically typed functional language with metaprogramming capabilities, that is based on
the lambda calculus. We have formally defined the core of the language using small-step
operational semantics together with inference rules describing the static type system. This
language is based on the simply typed lambda calculus, extended with metaprogramming
constructs for handling unknowns and model types. Moreover, we also proved type safety
for the core language.
We introduce the concept of higher-order acausal models (HOAMs), where models
can be passed around as first class citizens in the language. By giving examples from the
electrical and mechanical domain, we show the expressive modeling power, and also argue that several language constructs in Modelica can be subsumed or expressed by using
HOAMs. We conclude that HOAMs, demonstrated by using MKL, give a high expressiveness for modeling continuous-time acausal systems. However, for hybrid systems,
further research is needed to draw any general conclusions.
We have earlier concluded that a preferable approach of growing an EOO language
is that the user can add new language constructs, without the need of language changes.
The fifth and last research question concerns the possibility to design a language where
not only modeling constructs can be extended by the user, but also semantics for using
models (i.e., meta-operations on models).
The solution that we have investigated using MKL is to put the semantics for defining
EOO language constructs such as ports, equations, initial value definitions, and probes
into MKL libraries. Then, instead of informally specifying e.g., elaboration and simulation semantics in a separate language specification, we have put the formal executable
specification of the semantics into MKL libraries. These libraries can then be used to
inspect, analyze, and transform models using metaprogramming techniques. Our initial
experimental attempts include full elaboration of generating flat form of DAEs from MKL
source models, simulating the DAE using numerical DAE solvers, and to generate flat
Modelica code from MKL models. We have also compared and discussed our connection
semantics with Modelica’s approach.
An MKL interpreter has been implemented to verify and evaluate our solution. We
have verified by testing at a system level that models in MKL and Modelica behave similarly. Performance tests have also been conducted, where the main conclusion is that the
214
14 Concluding Remarks
elaboration phase is scalable.
Finally, we regard our work with the research language MKL as a first attempt of
using metaprogramming techniques with intensional analysis of models within the EOO
language area, i.e., the ability to defining both reusable model libraries as well as reusable
libraries for manipulating models within the same language. The approach has been evaluated on a non-trivial set of continuous-time models and our hope is that this work should
inspire for future research in the field where more complex models (e.g., multi-body and
fluid systems) as well as other uses (e.g., optimization, grey-box system identification, and
model reductions) can be realized using metaprogramming techniques within the same
language.
14.2
Future Work
Compared to other language paradigms, EOO languages can be seen as a fairly young
field. However, new opportunities and problems arise when we introduce concepts from
the computer science field in general and the programming language theory field in particular. Examples of such concepts are higher-order functions and metaprogramming
techniques. Our work in this thesis is an attempt to go in such a direction. Nevertheless,
there are still many outstanding issues and interesting problems left for future research.
In the following chapter we highlight some of them.
14.2.1 Extensional Metaprogramming
We have in this thesis described how we use metaprogramming for intensional analysis
of models by inspecting and traversing their content. In Chapter 12, we have given an
example program for how models can be simulated by using an external DAE solver.
Such a solver needs a residual function that computes values based on the DAE. In the
example we compute this vector value by interpretation, i.e., we traverse the system of
equations and compute the resulting value. However, an idea for future work is to utilize
extensional metaprogramming [129] for code generation of a function to compute the
residual before the simulation. The hypothesis would be that if the generated code is justin-time compiled, we could get simulation performance comparable to simulation systems
that statically compile the residual. We believe that multi-stage programming [141, 143]
could be the right choice because this also conforms to a statically typed environment. We
have so far performed preliminary tests of multi-stage programming in an MKL extension,
where we can simulate the system using extensional metaprogramming. However, our
current test prototype is interpreted and therefore only limited speedup is gained. It has
been shown that e.g. in MetaOCaml [31], good speedups have been achieved. However,
several research challenges remain, where one of them is efficient integration with the
runtime environment for the generated residual function and the numerical solver system
(e.g., Sundials [68]).
14.2.2 Hybrid and Structural Dynamic Systems
In this thesis we have focused on continuous-time systems. We do not currently see any
major challenges of defining simple hybrid constructs directly within MKL, e.g., to define
14.2 Future Work
215
a pre and reinit construct similar to Modelica:
let reinit : <Bool -> Real -> Real -> Eqs>
let pre: <Real -> Real>
A reinit equation could then be defined as
reinit (x >=. 0.) v ((pre v) *. -.1.)
where the first argument is the condition, the second argument the unknown that should
be reinitialized, and the third argument the expression if the event occurs.
However, how a more general solution can be created is more interesting. For example, that if-expressions are applicable for models as well, where the guard can be an
unknown. In the general case, the aim would be that any expression could be switched if
the guard changes over time. Because models are first class in MKL, this would imply that
we obtain a structurally dynamic system, where instances of models can switch over time.
Structurally dynamic systems with a fixed number of states have previously been developed in MOSILAB [112]. Other research results within this area are Functional Hybrid
Modeling (FHM) [62, 109] and the research language Sol by Zimmer [155]. We believe
that MKL could potentially be a good framework to further explore structural dynamic
systems.
14.2.3 Code Generation and Time Aspects
To achieve high confidence of cyber-physical systems, i.e., systems that mix physical
dynamics with software and networks, it is vital that such systems can be modeled and
simulated at design time. Hence, it is necessary that both the physical model of the plant
and the model of the controller reflect the reality of the real physical system together with
generated code running on embedded computer systems. One major problem when designing embedded systems today is the non- deterministic behavior of computation, i.e.,
it is very hard to estimate the timing of executing embedded code [87]. Traditionally,
simulated controllers are idealized to take zero time for computation, resulting in different dynamic behavior between the simulated system and the real system. Synchronous
languages [14] used for code generation of discrete-time systems are predictable and
repeatable, but currently lack a sound integration with acausal modeling languages with
continuous-time behavior. To mitigate these issues, the research challenge would be to
establish a way of automatically extract timing information for the target platform for
code generation and then include these timings into the simulated system. The simulated
system should closely match the real system; giving higher confidence of the modeled
system at an early stage of the system design process. We believe that MKL could be a
good platform to experiment with such a design.
14.2.4 Structural Constraint Delta
We do not expect that it is too difficult to add the structural constraint delta concept to
the type system of MKL’s. However, it is more challenging to make it flexible and not
dependent on built-in functionality, e.g., that the type system must explicitly know the
difference between an ElectricalBranch, the independent variable time and an
216
14 Concluding Remarks
ordinary equation. Hence, there must be a way to describe in the language what kind of
construct that contributes to constraint delta.
14.2.5 Polymorphism, Type Classes, and Algebraic Data Types
MKL is a small research language that lacks basic functionality that you expect from a
functional language. The most important constructs that would be useful are parametric
polymorphism, type classes, and algebraic data types. Adding these language features
might be less of a research challenge and more of a development work. However, further
investigation must be conducted to see how these language constructs interact with the
model type presented in this thesis.
14.2.6 Efficient Compilation
The current implementation prototype of MKL is interpreted. However, to make this solution useful in practice, we believe that a compiled system should be developed. One
alternative would be to implement the compiler and then to use e.g., LLVM [86] as the
backend. Another alternative would be to use an existing functional programming language as the backend, e.g., to generate OCaml code that can later be compiled and executed.
14.2.7 More Complex Modeling
Further case studies and experiments on more advanced modeling tasks should be investigated, to see how far MKL can be used. For example, case studies of implementing fluid
systems or multi-body systems could be the next step. In the fluid case, Modelica’s new
stream connector is a interesting construct to study [104]. Moreover, other constructs that
could be investigated is the possibility to add partial differential equations.
14.2.8 Uses Beyond Simulation
We have in this thesis showed how to use models in two ways; for simulation and for
export to flat Modelica code. However, there are many other potential uses of models. For
example, the work by Åkesson et. al. [5] on optimization of Modelica models. Casella et.
al. [34] propose several uses of models besides simulation, where model reduction is one
application area. Another application area could be grey box system identification [88],
where the equations for the model are known and parameters should be estimated by
using measured data from a real system. We see as interesting future work to explore the
possibility to use the MKL approach of implementing the semantics of these uses into
MKL libraries.
A
Syntax of MKL
In this appendix we define the concrete syntax for MKL 1.01 as well as an abstract syntax
for the intermediate language of the prototype implementation.
A.1 Concrete Syntax
A.1.1 Notational Conventions
Terminal symbols are reserved words written with bold typewriter font (e.g., let, if),
text enclosed between double quotes (e.g. "="."("), or tokens written in upper case
(e.g., UINT, IDENT). Nonterminal symbols are written using lower case letters and
typewriter font. Enclosing text in curly brackets (“{” and “}”) means repetition
zero or more times. Enclosing text in square brackets (“[” and “]”) indicates that the
item is optional.
A.1.2 Comments
Comments are sequences of characters between /* and */. Comments may be properly
nested. One line comments start with // where the following sequence of characters on
the same line is the comment.
A.1.3 Lexical Structure
The input sequence of characters are assumed to be Unicode 5.2.02. The following tokens
are defined during lexical analysis:
1 In previous work, we published a technical report about MKL and a lambda calculus for connection semantics [17]. The semantics for that language and the one presented in this thesis are not the same.
2 http://www.unicode.org/
217
218
A
Syntax of MKL
• An identifier IDENT is a non-empty sequence of letters (A,. . . ,Z and a,. . . ,z), digits
(0,. . . ,9), and underscore (_), where the first character must not be a digit.
• An unsigned integer constant UINT is a non-empty sequence of digits (0,. . . ,9).
• An unsigned real constant UREAL is an unsigned integer constant followed by a
dot (.), possibly followed by an unsigned integer constant, possibly followed by
exponential symbols (E and e), which is followed by an unsigned integer constant,
possibly prepended with a sign character (+ or -). Examples 12., 91.2, 2e8, and
3.12e-2.
• A string constant STRING is a sequence of character between quotes ("), where
the character sequence can contain escape sequences, each starting with the escape
character \. Possible escape sequences are horizontal tab (\t), newline (\n), double quote (\"), and escape character (\\).
• A primitive constant PRIMITIVE is a built-in constant or function, represented
as a sequence of letters, where the start of the sequence is @@. For example
@@int_mul.
A.1.4
Reserved Words
The following are reserved words, that may not be used as identifiers.
Array
Set
fun
snd
DAESolver
String
if
then
A.1.5
Top-Level
Int
else
in
true
List
error
include
type
Map
false
let
val
top ::=
let letpat param { "->" param }
"=" expr top
| let letpat "=" expr top
| let letpat ":" ty "=" expr top
| let letpat ":" ty top
| type IDENT top
| type IDENT "=" ty top
| include IDENT top
| EOF
A.1.6
ty
Real
fst
match
when
Let binder with params
Let binder
Let binder with type
Let unknown with type
Type declaration
Type synonymous
Include file
Types
::=
tyarrow
| tyarrow "=>" ty
tyarrow ::=
Arrow type for Map
Arrow type for functions
219
A.1 Concrete Syntax
tyatom
| tyatom "->" tyarrow
tyatom ::=
IDENT
| Int
| Real
| Bool
| String
| "(" ")"
| "[" ty "]"
| List tyatom
| "{" ty "}"
| Array tyatom
| "(" ty { "," ty } ")"
| "<" ">"
| "<" ty ">"
| Map tyatom tyatom
| Set tyatom
| DAESolver
Identifier
Integer type
Real type
Boolean type
String type
Unit type
List type
Array type
Tuple type
Any model type
Specific model type
Map type
Set Type
DAE Solver instance type
A.1.7 Expressions
expr ::=
fun IDENT ":" tyatom "->" expr
Function abstraction
| let letpat param { "->" param }
Local let binders
"=" expr in
| let pat_atom "=" expr in expr
| let letpat ":" ty "=" expr in expr
| if expr then expr else expr
IF-expression
| let letpat ":" ty in expr
Local let unknown
| match expr with matchcases
Match expression
| Array "." IDENT { atom }+
Array operation
| Map "." IDENT { atom }
Map operation
| Set "." IDENT { atom }
Set operation
| DAESolver "." IDENT { atom }
DAESolver operation
| cons
letpat ::=
IDENT
| "_"
Simple let pattern
param ::=
IDENT ":" tyatom
Parameter with type
cons ::=
op
| op "::" cons
Cons
op ::=
Operators
220
A
Syntax of MKL
app_left
| op operator op
operator ::=
"="
|
| "*"
|
| ">=" |
| "/." |
| "!=." |
| "++" |
"~="
"/"
"!="
"<."
"!"
"--"
|
|
|
|
|
|
"mod"
"<"
"+."
"<=."
"&&"
"--."
| "+"
|"<="
| "-."
| ">."
| "||"
| "^"
|
|
|
|
|
|
"-"
">"
"*."
">=."
";"
"^."
app_left ::=
atom
| app_left atom
| fst atom
| snd atom
| val atom
| error atom
Application
First tuple element
Second tuple element
Model value constructor
Error
atom ::=
IDENT
| true
| false
| UINT
| UREAL
| STRING
| PRIMITIVE
| "[" "]"
| "[" expr { "," expr } "]"
| "{" expr { "," expr } "}"
| "(" ")"
| "(" expr { "," expr } ")"
Identifier
True
False
Integer literal
Real (float) literal
String literal
Primitive operation
Empty list
List
Array
Unit literal
Tuple
A.1.8
Pattern Matching
matchcases ::=
Match cases
"|" pattern [when expr] "->" expr
| matchcases "|" pattern [when expr]
"->" expr
pattern ::=
pat_op
| pat_op "::" pattern
pat_op ::=
pat_left
| pat_op OP pat_op
pat_left ::=
pat_atom
Cons pattern
Pattern operator
221
A.2 Abstract Syntax
|
|
|
|
pat_left pat_atom
fst pat_atom
snd pat_atom
val IDENT ":" tyatom
pat_atom ::=
IDENT
| true
| false
| UINT
| UREAL
| STRING
| "(" ")"
| "’" atom
| "[" "]"
| "[" pattern { "," pattern } "]"
| UK COLON tyatom
| "(" pattern { "," pattern } ")"
| "_"
First elem of a tuple
Second elem of a tuple
Model value pattern
Pattern variable
True
False pattern
Unsigned Integer literal
Unsigned Real literal
String literal
Unit literal
Pattern expression
Empty list
List pattern
Unknown pattern
Tuple pattern
Wildcard pattern
A.2 Abstract Syntax
This section defines an abstract syntax for representing an intermediate language of MKL.
The result of parsing the concrete syntax is translated into an abstract syntax tree described in this section. The most essential translation steps are:
• File inclusion (see Section 12.1.1).
• Desugar top-level constructs, meaning substitution of type synonymous and translation of top let-binders into local binders.
• Pattern compilation/translation. The process translates match-expressions into
primitives for deconstructing models, lists and tuples.
• Type checking and model lifting (see Chapter 10 for a formal treatment of the core).
The objective of the abstract syntax for this intermediate language is to give the reader of
this thesis a better understanding of which other language constructs that are part of the
language, besides what was presented about the core. The aim is not to be a full language
specification. Basic definitions:
Variables
Unknowns
Integers
Constants
x, y, z ∈ X
u∈U
i∈Z
c ∈ C = {true, false} ∪ Int ∪ Real ∪ String
222
A
A.2.1
Syntax of MKL
Types
Types in the language are defined as follows:
τ ::=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bool
Int
Real
String
τ →τ
()
[τ ]
(τi i∈1..n )
<τ >
<>
Bot
pseudoi
{τ }
τ => τ
Set τ
DAESolver
Boolean type
Integer type
Real type
String type
Function type
Unit type
List type
Tuple type
Model type
Any model type
Bot type
User defined pseudo type
Array type
Map type
Set type
DAESolver type
Comments:
• The four first types Bool, Int, Real, and String is represented as the ground
type Γ in Chapter 10.
• All types, except for Bot type Bot, and the user defined pseudo type pseudoi can
be syntactically defined by the user (compare with the types of the concrete syntax).
• The bot type Bot is used as the type the element of an empty list or an empty array.
• Each pseudo type is assigned a unique id (i of pseudoi ). The pseudo type is created
by giving it a name using the type syntax, e.g., type Eqs creates a new pseudo
type. All places after this definition where type Eqs is used will be the same pseudo
type.
• The DAESolver solver type is the type of an instance of the ADT DAESolver.
223
A.2 Abstract Syntax
A.2.2 Expressions
e ::=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Comments:
x
λx : τ.e
ee
c
u:τ
ν(τ )
[email protected]
val e : τ
decon(e, d, e, e)
fix e
if e then e else e
e == e
e :: e
[]
lcase(e, x, x, e, e)
(ei i∈1..n )
proj i from e
adt
adtop ei i∈1..n
error e
Variable
Lambda abstraction
Application
Constant
Unknown
New unknown creation
Model application
Model value
Model deconstructor
Fixed-point
If-expression
Equality test
List constructor
Empty list
List case
Tuple
Projection
Built-in ADT
Built-in ADT operation
User defined error
• The list case expression lcase(v, x1 , x1 , e1 , e2 ) deconstructs a list v. If v has the
shape of a cons value v1 :: v2 , v1 is substituted for x1 and v2 substituted for x2 in
e1 that is the resulting expression. If v has the shape of an empty list, expression e2
is the resulting expression.
• Projection proj i from v returns element number i from v, where v is assumed
to be have the shape of a tuple.
• Expression adt is the value of a type {τ }, τ => τ , Set τ , or DAESolver.
• Expression adtop vi i∈1..n calls a built-in ADT operation.
• Expression error v stops execution of the program and returns an error message
v, where v is assumed to have type String.
A.2.3 Values
v ::=
|
|
|
|
|
|
|
|
λx : τ.e
c
u:τ
[email protected]
val v : τ
v :: v
[]
(vi i∈1..n )
adt
Lambda abstraction
Constant
Unknown
Model application
Model value
List constructor
Empty list
Tuple
Built-in ADT
224
A
Syntax of MKL
B
Built-in Abstract Data Types
All types of functions are stated using curried form, but partial application is not syntactically allowed. Type variables for the built-in abstract data types (ADTs) are written with
a prepended single quote, e.g., ’a.
B.1 Array
Array operations for a random access array.
Array.length : {’a} -> Int
An expression (Array.length a) evaluates to the length (the number of elements) of
array a.
Array.make : Int -> ’a -> {’a}
An expression (Array.make n e) creates a new array of length n filled with element e.
Array.get : {’a} -> Int -> ’a
An expression (Array.get a k) evaluates to element with index k in array a. The
first element has number 0. If k is outside range 0 to Array.length a - 1, then the
program terminates.
Array.set : {’a} -> Int -> ’a -> ()
An expression (Array.set a k e) destructively updates array a at index k with element e. If k is outside range 0 to Array.length a - 1, then the program terminates.
225
226
B.2
B
Built-in Abstract Data Types
Set
A pure functional Set.
Set.size : Set ’a -> Int
An expression (Set.size s) evaluates to the cardinality (the number of elements) of
set s.
Set.empty : Set ’a
An expression (Set.empty) evaluates to an empty set 1 .
Set.add : ’a -> Set ’a -> Set ’a
An expression (Set.add e s) evaluates to a new set that contains all element of s plus
element e.
Set.mem : ’a -> Set ’a -> Bool
An expression (Set.mem e s) evaluates to true if element e exists in set s, else false.
Set.remove : ’a -> Set ’a -> Set ’a
An expression (Set.remove e s) evaluates to a new set containing all elements of s
except for e.
Set.toList : Set ’a -> [’a]
An expression (Set.toList s) evaluates to a list representation of set s.
B.3
Map
A purely functional finite map.
Map.size : (’a => ’b) -> Int
An expression (Map.size m) evaluates to the number of elements in m.
Map.empty : (’a => ’b)
An expression (Map.empty) evaluates to a new empty map.
1 The type of the element of the Set is here expressed as a type variable, but will internally use type Bot
during type checking.
B.3 Map
227
Map.add : ’a -> ’b -> (’a => ’b) -> (’a => ’b)
An expression (Map.add k v m) evaluates to a new map that contains all key/value
pairs of map m plus a new a binding between key k and value v. If k already exists in m,
the previous binding is removed.
Map.find : ’a -> (’a => ’b) -> ’b
An expression (Map.find k m) evaluates to the value bound to key k in map m. It
terminates the program if the element is not found. Note: use Map.mem before calling
Map.find.
Map.mem : ’a -> (’a => ’b) -> Bool
An expression (Map.mem k m) evaluates to true if there exists a binding of key k in
map m, else false.
Map.remove : ’a -> (’a => ’b) -> (’a => ’b)
An expression (Map.remove k m) evaluates to a new map containing all key/value pairs
in map m, except for a binding of key k that is removed.
Map.toList : (’a => ’b) -> [(’a,’b)]
An expression (Map.toList m) evaluates to a list of tuples containing all key/value
pairs in map m.
228
B.4
B
Built-in Abstract Data Types
DAESolver
ADT DAESolver interfaces the IDA solver from the SUNDIALS suite [68].
DAESolver.make : {Real} -> {Real} -> {Real} ->
(Real -> {Real} -> {Real} -> [Real]) -> DAESolver
An expression (DAESolver.make yy yp id res) evaluates to a new instance of a
DAE solver. Argument yy is an array of initial values for vector y and argument yp the
initial values for vector ẏ. Argument id is an array of Real specifying a differential
variable (value 1.0) or an algebraic variable (value 0.0). Argument id is used for correction of initial conditions. Argument res is the supplied residual function that has type
(Real -> {Real} -> {Real} -> [Real]), where its first parameter is the independent variable of time, parameter 1 the dependent variable vector y(t) and parameter
2 the vector ẏ(t). The output residual is returned as a list of Real.
DAESolver.step : Real -> DAESolver -> Real
An expression (DAESolver.step t s) integrates the DAE over a time, where t is the
next time a computed result is desired and s is the DAESolver instance. The result of
the function call is the time reached by the solver. If the returned time is zero, an error
occurred. The result of the computation is destructively updated in the arrays supplied to
DAESolver.make.
C
Big-step Semantics of MKL Core
e|U ⇒ e|U
Evaluation Rules
λx : τ.e | U1 ⇒ λx : τ.e | U1
(BS-ABS)
e1 | U1 ⇒ λx : τ.e3 | U2
e2 | U2 ⇒ v1 | U3
[x 7→ v1 ]e3 | U3 ⇒ v2 | U4
e1 e2 | U1 ⇒ v2 | U4
c | U1 ⇒ c | U1
(BS-CONST)
(BS-APPABS)
e1 | U1 ⇒ c | U2
e2 | U2 ⇒ v2 | U3
v3 = δ(c, v2 )
e1 e2 | U1 ⇒ v3 | U3
u∈
/ U1
ν(τ ) | U1 ⇒ u : <τ > | U1 ∪ {u}
e1 | U1 ⇒ v1 | U2
val e1 : τ | U1 ⇒ val v1 : τ | U2
(BS-APPCONST)
(BS-NEWUK)
e1 | U1 ⇒ v1 | U2
e2 | U2 ⇒ v2 | U3
e1 @ e2 | U1 ⇒ v1 @ v2 | U3
(BS-MODAPP)
(BS-MODVAL)
e1 | U1 ⇒ v1 | U2
match(v1 , d, e2 , e′2 )
e′2 | U2 ⇒ v2 | U3
decon(e1 , d, e2 , e3 ) | U1 ⇒ v2 | U3
e1 | U1 ⇒ v1 | U2
¬match(v1 , d, e2 , e′2 )
e3 | U2 ⇒ v3 | U3
decon(e1 , d, e2 , e3 ) | U1 ⇒ v3 | U3
229
(BS-UK)
u : τ | U1 ⇒ u : τ | U1
(BS-DECON-T)
(BS-DECON-F)
230
C Big-step Semantics of MKL Core
match(e, d, e, e)
Match
match(u : τ, uk : τ, e, e)
(BS-M-UK)
match(val v : τ, val x : τ, e, (λx : τ.e) v)
(BS-M-MVAL)
match(v1 @ v2 , x1 @ x2 , e, (λx1 : <>.λx2 : <>.e) v1 v2 )
(BS-M-MAPP)
The big-step semantics above is defined for language λ<>
L using syntax in Figure 10.1 on
page 138.
D
MKL Library
This appendix lists the MKL source code of the MKL library. The figure below outlines
dependencies between different modules in the library.
231
232
D MKL Library
D.1 Base
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
let
(mod) : Int -> Int -> Int = @@int_mod
(+) : Int -> Int -> Int = @@int_add
(-) : Int -> Int -> Int = @@int_sub
(*) : Int -> Int -> Int = @@int_mul
(/) : Int -> Int -> Int = @@int_div
(<) : Int -> Int -> Bool = @@int_less
(<=) : Int -> Int -> Bool = @@int_less_equal
(>) : Int -> Int -> Bool = @@int_great
(>=) : Int -> Int -> Bool = @@int_great_equal
(!=) : Int -> Int -> Bool = @@int_not_equal
(+.) : Real -> Real -> Real = @@real_add
(-.) : Real -> Real -> Real = @@real_sub
(*.) : Real -> Real -> Real = @@real_mul
(/.) : Real -> Real -> Real = @@real_div
(<.) : Real -> Real -> Bool = @@real_less
(<=.) : Real -> Real -> Bool = @@real_less_equal
(>.) : Real -> Real -> Bool = @@real_great
(>=.) : Real -> Real -> Bool = @@real_great_equal
(!=.) : Real -> Real -> Bool = @@real_not_equal
(!) : Bool -> Bool = @@bool_not
(&&) : Bool -> Bool -> Bool = @@bool_and
(||) : Bool -> Bool -> Bool = @@bool_or
(--) : Int -> Int = @@int_neg
(--.) : Real -> Real = @@real_neg
print : String -> () = @@print
bool2string : Bool -> String = @@bool2string
int2string : Int -> String = @@int2string
real2string : Real -> String = @@real2string
int2real : Int -> Real = @@int2real
real2int : Real -> Int = @@real2int
string2bool : String -> Bool = @@string2bool
string2int : String -> Int = @@string2int
string2real : String -> Real = @@string2real
isBoolString : String -> Bool = @@isboolstring
isRealString : String -> Bool = @@isrealstring
isIntString : String -> Bool = @@isintstring
sin : Real -> Real = @@sin
cos : Real -> Real = @@cos
tan : Real -> Real = @@tan
asin : Real -> Real = @@asin
acos : Real -> Real = @@acos
atan : Real -> Real = @@atan
sinh : Real -> Real = @@sinh
cosh : Real -> Real = @@cosh
tanh : Real -> Real = @@tanh
ceil : Real -> Real = @@ceil
floor : Real -> Real = @@floor
log : Real -> Real = @@log
log10 : Real -> Real = @@log10
sqrt : Real -> Real = @@sqrt
exp : Real -> Real = @@exp
(^.) : Real -> Real -> Real = @@exponentiation
substr : String -> Int -> Int -> String = @@string_substr
strlen : String -> Int = @@string_strlen
(++) : String -> String -> String = @@string_concat
D.2 Modeling
let printLine s:String -> () =
let _ = print s in print "\n"
let printIntLine i:Int -> () =
printLine (int2string i)
let printRealLine i:Real -> () =
printLine (real2string i)
D.2 Modeling
include Base
type Eqs
type Equations = <Eqs>
type Signal = <Real>
let der : <Real -> Real>
let EquationSysNode : <Eqs -> Eqs -> Eqs>
let Eq : <Real -> Real -> Eqs>
let Init : <Real -> Real -> Eqs>
let InitGuess : <Real -> Real -> Eqs>
let time : <Real>
let probe : <String -> Real>
let (=) : <Real -> Real -> Eqs> = Eq
let (;) : <Eqs -> Eqs -> Eqs> = EquationSysNode
D.3 Electrical
include Modeling
type ElectricalNode
type Electrical = <ElectricalNode>
let ElectricalBranch :
<Real -> Real -> ElectricalNode -> ElectricalNode -> Eqs>
let ElectricalRefBranch : <Real -> Real -> ElectricalNode -> Eqs>
type Voltage = <Real>
type Current = <Real>
D.4 AnalogElectrical
include Electrical
include Mechanical
let Resistor R:Real -> p:Electrical -> n:Electrical -> Equations =
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
R *. i = v
let Capacitor C:Real -> p:Electrical -> n:Electrical -> Equations =
let i:Current in
let v:Voltage in
233
234
D MKL Library
ElectricalBranch i v p n;
C *. (der v) = i
let Inductor L:Real -> p:Electrical -> n:Electrical -> Equations =
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
L *. (der i) = v
let Ground p:Electrical -> Equations =
let i:Current in
let v:Voltage in
ElectricalRefBranch i v p;
v = 0.
let SineVoltage V:Real -> f:Real -> p:Electrical -> n:Electrical ->
Equations =
let PI = 3.1415 in
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
v = V *. sin(2. *. PI *. f *. time)
let ConstantVoltage V:Real -> p:Electrical -> n:Electrical ->
let i:Current in
let v:Voltage in
ElectricalBranch i v p n;
v = V
Equations =
let EMF k:Real -> p:Electrical -> n:Electrical -> flange:Rotational ->
Equations =
let i:Current in
let v:Voltage in
let w:AngularVelocity in
let phi:Angle in
let tau:Torque in
ElectricalBranch i v p n;
RotationalRefBranch tau phi flange;
w = der(phi);
k *. w = v;
tau = k *. i
let VoltageSensor output:Signal -> p:Electrical -> n:Electrical ->
Equations =
ElectricalBranch 0. output p n
let PotentialSensor output:Signal -> p:Electrical -> Equations =
ElectricalRefBranch 0. output p
let CurrentSensor output:Signal -> p:Electrical -> n:Electrical ->
Equations =
ElectricalBranch output 0. p n
D.5 Mechanical
include Modeling
D.6 RotationalMechanical
type RotationalNode
type Rotational = <RotationalNode>
let RotationalBranch :
<Real -> Real -> RotationalNode -> RotationalNode -> Eqs>
let RotationalRefBranch : <Real -> Real -> RotationalNode -> Eqs>
type AngularVelocity = <Real>
type AngularAcceleration = <Real>
type Angle = <Real>
type Torque = <Real>
D.6 RotationalMechanical
include Mechanical
let Spring c:Real -> flangeA:Rotational -> flangeB:Rotational ->
Equations =
let tau:Torque in
let relphi:Angle in
RotationalBranch tau relphi flangeB flangeA;
tau = c *. relphi
let Damper d:Real -> flangeA:Rotational -> flangeB:Rotational ->
Equations =
let tau:Torque in
let relphi:Angle in
RotationalBranch tau relphi flangeB flangeA;
tau = d *. der(relphi)
let Inertia J:Real -> flangeA:Rotational -> flangeB:Rotational ->
Equations =
let tauA:Torque in
let tauB:Torque in
let phiA:Angle in
let phiB:Angle in
let phi:Angle in
let w:AngularVelocity in
let a:AngularAcceleration in
RotationalRefBranch tauB phiB flangeB;
RotationalRefBranch tauA phiA flangeA;
phiA = phi;
phiB = phi;
w = der(phi);
a = der(w);
J *. a = tauA +. tauB
let IdealGear ratio:Real -> flangeA:Rotational -> flangeB:Rotational ->
Equations =
let tauA:Torque in
let tauB:Torque in
let phiA:Angle in
let phiB:Angle in
RotationalRefBranch tauA phiA flangeA;
RotationalRefBranch tauB phiB flangeB;
phiA = ratio *. phiB;
0. = ratio *. tauA +. tauB
let Fixed angle:Real -> flangeB:Rotational -> Equations =
235
236
D MKL Library
let tau:Torque in
RotationalRefBranch tau angle flangeB
let ConstantTorque tau:Real -> flangeB:Rotational -> Equations=
let phi:Angle in
RotationalRefBranch tau phi flangeB
let Torque tau:Signal -> flangeB:Rotational -> Equations =
let phi:Angle in
RotationalRefBranch tau phi flangeB
let TorqueSensor tau:Signal -> flangeA:Rotational ->
flangeB:Rotational -> Equations =
RotationalBranch tau 0. flangeB flangeA
let AngleSensor phi:Signal -> flangeB:Rotational -> Equations =
RotationalRefBranch 0. (-.phi) flangeB
let SpeedSensor w:Signal -> flangeB:Rotational -> Equations =
let phi:Angle in
RotationalRefBranch 0. (-.phi) flangeB;
w = der(phi)
let AccSensor a:Signal -> flangeB:Rotational -> Equations =
let phi:Angle in
let w:AngularVelocity in
RotationalRefBranch 0. (-.phi) flangeB;
w = der(phi);
a = der(w)
let RelAngleSensor phiRel:Signal -> flangeA:Rotational ->
flangeB:Rotational -> Equations =
RotationalBranch 0. phiRel flangeB flangeA
let RelSpeedSensor w:Signal -> flangeA:Rotational ->
flangeB:Rotational -> Equations =
let phiRel:Angle in
RotationalBranch 0. phiRel flangeB flangeA;
w = der(phiRel)
let RelAccSensor a:Signal -> flangeA:Rotational ->
flangeB:Rotational -> Equations =
let phiRel:Angle in
let w:AngularVelocity in
RotationalBranch 0. phiRel flangeB flangeA;
w = der(phiRel);
a = der(w)
D.7 Elaboration
include Modeling
type
type
type
type
type
Expr = <>
Node = <>
Unknown = <>
Branch = <>
NodeMap = (Node => Unknown)
D.7 Elaboration
type
type
type
type
type
type
type
type
type
NodeMapList = [(Node,Unknown)]
BranchSet = (Set Branch)
BranchList = [Branch]
ExprMap = (Node => Expr)
ExprList = [(Node, Expr)]
ProbeMap = (String => [Signal])
InitValMap = (<Real> => (Real,Bool))
UkSet = (Set <Real>)
UkMap = (Signal => (Int,Bool))
let elaborateConnections isBranch:(<> -> Bool) ->
isRefBranch:(<> -> Bool) ->
model:Equations ->
Equations =
let addNode node:Node -> nodemap:NodeMap -> NodeMap =
if Map.mem node nodemap then nodemap
else let u:<Real> in Map.add node u nodemap
in
let sumexpr branches:BranchSet -> ExprMap =
let worker branches:BranchList -> emap:ExprMap -> ExprMap =
match branches with
| (b i v p n)::bs when isBranch b ->
let emap1 = if Map.mem p emap
then Map.add p ((Map.find p emap) +. i) emap
else Map.add p i emap in
let emap2 = if Map.mem n emap1
then Map.add n ((Map.find n emap1) -. i) emap1
else Map.add n (-. i) emap1 in
worker bs emap2
| (b i v p)::bs when isRefBranch b ->
let emap1 = if Map.mem p emap
then Map.add p ((Map.find p emap) +. i) emap
else Map.add p i emap in
worker bs emap1
| [] -> emap
in worker (Set.toList branches) (Map.empty)
in
let sumzero m:Equations -> branches:BranchSet -> Equations =
let worker elist:ExprList -> Equations =
match elist with
| (_,e)::es -> e = 0.; worker es
| [] -> m
in worker (Map.toList (sumexpr branches))
in
let potentials model:Equations -> (Equations,BranchSet) =
let worker m:Equations -> nodemap:NodeMap ->
branchset:BranchSet -> (<>,NodeMap,BranchSet) =
match m with
| b i v p n when isBranch b ->
let nodemap2 = addNode n (addNode p nodemap) in
let eq = (v = (Map.find p nodemap2) -.
(Map.find n nodemap2)) in
(eq,nodemap2,Set.add m branchset)
| b i v p when isRefBranch b ->
let nodemap2 = addNode p nodemap in
237
238
D MKL Library
let eq = (v = (Map.find p nodemap2)) in
(eq,nodemap2,Set.add m branchset)
| e1 ; e2 ->
let (e1b,nodemap1,branchset1) =
worker e1 nodemap branchset in
let (e2b,nodemap2,branchset2) =
worker e2 nodemap1 branchset1 in
(e1b ; e2b, nodemap2, branchset2)
| _ -> (m,nodemap,branchset)
in
let (model,_,branchset) =
worker model (Map.empty) (Set.empty)
in (model,branchset)
in
let (model2,branchset2) = potentials model in
sumzero model2 branchset2
let addProbe s:String -> u:Signal -> ps:ProbeMap =
if Map.mem s ps then Map.add s (u::(Map.find s ps)) ps
else Map.add s [u] ps
let elaborateProbes model:Equations -> (Equations,ProbeMap) =
let elab e:<> -> ps:ProbeMap -> (<>,ProbeMap) =
match e with
| ’probe (val s:String) -> let u:Signal in (u,addProbe s u ps)
| e1 e2 ->
let (e1b,ps1) = elab e1 ps in
let (e2b,ps2) = elab e2 ps1 in
(e1b e2b,ps2)
| _ -> (e,ps)
in elab model (Map.empty)
let initValues eqs:Equations -> InitValMap =
let get eqs:Equations -> acc:InitValMap -> InitValMap =
match eqs with
| e1 ; e2 -> get e2 (get e1 acc)
| Init x (val v:Real) -> Map.add x (v,false) acc
| InitGuess x (val v:Real) -> Map.add x (v,true) acc
| _ -> acc
in get eqs (Map.empty)
let unknowns eqs:Equations -> UkSet =
let get e:<> -> acc:UkSet -> UkSet =
match e with
| e1 e2 -> get e2 (get e1 acc)
| ’time -> acc
| uk:<Real> -> Set.add e acc
| _ -> acc
in get eqs (Set.empty)
let noUnknowns eqs:Equations -> Int =
Set.size (unknowns eqs)
let noEquations eqs:Equations -> Int =
match eqs with
| e1 ; e2 -> (noEquations e1) + (noEquations e2)
| e1 = e2 -> 1
| _ -> 0
D.8 MechatronicElaboration
let realUnknowns eqs:Equations -> (Int,UkMap) =
let get e:<> -> acc:(Int,UkMap) -> (Int,UkMap) =
match e with
| e1 e2 -> get e2 (get e1 acc)
| ’time -> acc
| der x ->
(match x with
| uk:<Real> ->
let (k,ukmap) = acc in
if Map.mem e ukmap
then (k,Map.add e (fst (Map.find e ukmap),true) ukmap)
else ((k+1,Map.add e (k,true) ukmap))
| _ -> error "Illegal diffrentiation of expression")
| uk:<Real> ->
if Map.mem e (snd acc) then acc
else ((fst acc)+1,Map.add e (fst acc,false) (snd acc))
| e1 -> acc
in get eqs (0,(Map.empty))
let makeUkMap eqs:Equations -> UkMap =
snd (realUnknowns eqs)
D.8 MechatronicElaboration
include Mechanical
include Electrical
include Elaboration
let isMechatronicBranch b:<> =
match b with
| ’ElectricalBranch -> true
| ’RotationalBranch -> true
| _ -> false
let isMechatronicRefBranch b:<> =
match b with
| ’ElectricalRefBranch -> true
| ’RotationalRefBranch -> true
| _ -> false
let elaborate model:Equations -> (Equations,ProbeMap) =
let (model2,probes) = elaborateProbes model in
(elaborateConnections isMechatronicBranch
isMechatronicRefBranch model2,probes)
D.9 Simulation
include MechatronicElaboration
type StepVal = (Real,[Real])
type SimulationResult = ([String],[StepVal])
type Residual = Real -> {Real} -> {Real} -> [Real]
let makeResidual model:Equations -> ukmap:UkMap ->
239
240
D MKL Library
ctime:Real -> yy:{Real} -> yp:{Real} -> [Real] =
let realExpr e:<> -> Real =
match e with
| (val f:(Real -> Real -> Real)) e1 e2 ->
f (realExpr e1) (realExpr e2)
| (val f:(Real -> Real)) e1 -> f (realExpr e1)
| val v:Real -> v
| ’time -> ctime
| der x -> (match x with
| uk:Signal -> Array.get yp (fst (Map.find x ukmap))
| _ -> error "Derivatives only allowed on unknowns")
| uk:Signal -> Array.get yy (fst(Map.find e ukmap))
| _ -> error "Unsupported model construct"
in
let traverseEq m:Equations -> acc:[Real] -> [Real] =
match m with
| e1 ; e2 -> traverseEq e2 (traverseEq e1 acc)
| e1 = e2 -> (realExpr e1 -. realExpr e2) :: acc
| _ -> acc
in traverseEq model []
let makeInitValues model:Equations -> ukmap:UkMap -> ({Real},{Real}) =
let initvalmap = initValues model in
let size = Map.size ukmap in
let yy = Array.make size 0. in
let yp = Array.make size 0. in
let setvals initvals:[(Signal,(Real,Bool))] -> {Real} =
match initvals with
| (u,(v,_))::xs ->
let _ = Array.set yy (fst (Map.find u ukmap)) v in setvals xs
| [] -> yy
in (setvals (Map.toList initvalmap) , yp)
let makeStepVal currtime:Real -> yy:{Real} ->
probes:[(String,[Signal])] -> ukmap:UkMap -> StepVal =
let mkvals probes:[(String,[Signal])] -> [Real] =
match probes with
| (s,u::us)::ss -> (Array.get yy (fst(Map.find u ukmap)))::
(mkvals ((s,us)::ss))
| (s,[])::ss -> mkvals ss
| [] -> []
in (currtime,mkvals probes)
let makeProbeNames probes:[(String,[Signal])] -> n:Int -> [String] =
match probes with
| (s,u::us)::ss ->
let s2 = s ++ (if n > 1 then "_" ++ int2string n else "") in
s2::(makeProbeNames ((s,us)::ss) (n+1))
| (s,[])::ss -> makeProbeNames ss 1
| [] -> []
let initConditionCorrection ukmap:UkMap -> {Real} =
let id = Array.make (Map.size ukmap) 0. in
let worker uklist:[(Signal,(Int,Bool))] -> {Real} =
match uklist with
| (u,(i,true))::us -> let _ = Array.set id i 1.0 in worker us
| _::us -> worker us
| [] -> id
D.10 Export Modelica
241
in worker (Map.toList ukmap)
let revResult lst:[StepVal] -> acc:[StepVal] -> [StepVal] =
match lst with
| x::xs -> revResult xs (x::acc)
| [] -> acc
let simulate model:Equations -> steptime:Real -> endtime:Real ->
SimulationResult =
let (model2,probes) = elaborate model in
let probelist = Map.toList probes in
let ukmap = makeUkMap model2 in
let residual = makeResidual model2 ukmap in
let (yy,yp) = makeInitValues model2 ukmap in
let id = initConditionCorrection ukmap in
let state = DAESolver.make yy yp id residual in
let simloop currtime:Real -> acc:[StepVal] -> [StepVal] =
if currtime >=. endtime then acc
else
let stepval = makeStepVal currtime yy probelist ukmap in
let newtime = DAESolver.step steptime state in
if newtime == 0. then acc
else simloop (newtime +. steptime) (stepval::acc)
in
(makeProbeNames probelist 1,revResult (simloop 0. []) [])
let pprintSimulation res:SimulationResult -> String =
let (names,stepvals) = res in
let psteps step:[StepVal] -> first:Bool -> String =
match step with
| (t,x::xs)::xxs when first ->
real2string t ++ "\t" ++ psteps ((t,x::xs)::xxs) false
| (t,x::xs)::xxs ->
real2string x ++ "\t" ++ psteps ((t,xs)::xxs) false
| (t,[])::xxs -> "\n" ++ psteps xxs true
| [] -> ""
in psteps stepvals true
let printsim model:Equations -> steptime:Real -> endtime:Real -> () =
print (pprintSimulation (simulate model steptime endtime))
D.10 Export Modelica
include MechatronicElaboration
let mkvar uks:(Int,UkMap) -> e:<> -> String =
match uks with
| (_,ma) -> "uk" ++ int2string (fst (Map.find e ma))
let pprintModelica name:String ->
probelist:[(String,[Signal])] ->
model:Equations -> String =
let uks = realUnknowns model in
let real2modelicaString r:Real -> String =
if r <. 0. then "(" ++ real2string r ++ ")" else real2string r
in
let pprintUnknowns us:(Int,UkMap) -> initvalmap:InitValMap -> String =
242
D MKL Library
let initstr u:Signal -> String =
if Map.mem u initvalmap then
let (initval,guess) = Map.find u initvalmap in
"(start=" ++ real2string initval ++
(if guess then "" else ",fixed=true") ++ ")"
else ""
in
let prn us:[(Signal,(Int,Bool))] -> String =
match us with
| (u,_)::us -> " Real " ++ mkvar uks u ++
initstr u ++ ";\n" ++ prn us
| [] -> ""
in prn (Map.toList (snd us))
in
let pprintExpr expr:<> -> String =
match expr with
| e1 +. e2 -> "(" ++ pprintExpr e1 ++ " + " ++ pprintExpr e2 ++ ")"
| e1 -. e2 -> "(" ++ pprintExpr e1 ++ " - " ++ pprintExpr e2 ++ ")"
| e1 *. e2 -> pprintExpr e1 ++ " * " ++ pprintExpr e2
| e1 /. e2 -> pprintExpr e1 ++ " / " ++ pprintExpr e2
| -. e ->
"(-" ++ pprintExpr e ++ ")"
| e1 ^. e2 -> pprintExpr e1 ++ " ^ " ++ "(" ++ pprintExpr e2 ++ ")"
| ’der e ->
"der(" ++ pprintExpr e ++ ")"
| ’sin e ->
"sin(" ++ pprintExpr e ++ ")"
| ’cos e ->
"cos(" ++ pprintExpr e ++ ")"
| ’tan e ->
"tan(" ++ pprintExpr e ++ ")"
| ’asin e -> "asin(" ++ pprintExpr e ++ ")"
| ’acos e -> "acos(" ++ pprintExpr e ++ ")"
| ’atan e -> "atan(" ++ pprintExpr e ++ ")"
| ’sinh e -> "sinh(" ++ pprintExpr e ++ ")"
| ’cosh e -> "cosh(" ++ pprintExpr e ++ ")"
| ’tanh e -> "tanh(" ++ pprintExpr e ++ ")"
| ’sqrt e -> "sqrt(" ++ pprintExpr e ++ ")"
| ’exp e ->
"exp(" ++ pprintExpr e ++ ")"
| ’log e ->
"log(" ++ pprintExpr e ++ ")"
| ’log10 e -> "log10(" ++ pprintExpr e ++ ")"
| ’time -> "time"
| uk:<Real> -> mkvar uks expr
| val r:Real -> real2modelicaString r
in
let pprintEqs model:Equations -> String =
match model with
| e1 ; e2 -> pprintEqs e1 ++ pprintEqs e2
| e1 = e2 -> " " ++ pprintExpr e1 ++ " = " ++ pprintExpr e2 ++ ";\n"
| _ -> ""
in
let pprintOutput probes:[(String,[Signal])] -> n:Int -> String =
match probes with
| (s,u::us)::ss ->
" output Real " ++ s ++ (if n > 1 then "_" ++ int2string n
else "") ++
" = " ++ mkvar uks u ++ ";\n" ++ pprintOutput ((s,us)::ss) (n+1)
| (s,[])::ss -> pprintOutput ss 1
| [] -> ""
in
"model " ++ name ++ "\n" ++ pprintOutput probelist 1 ++
"protected\n" ++ pprintUnknowns uks (initValues model) ++
"equation\n" ++ pprintEqs model ++ "end " ++ name ++ ";"
D.11 Performance Test Source Code
243
let exportModelica name:String -> model:Equations -> String =
let (model2,probes) = elaborate model in
pprintModelica name (Map.toList probes) model2
D.11 Performance Test Source Code
The following program lists the MKL source code for the programs used in performance
testing. Note that MechSys is including MechsysBasics.
include AnalogElectrical
include RotationalMechanical
let ShaftElement flangeA:Rotational -> flangeB:Rotational ->
Equations =
let r1:Rotational in
Spring 8. flangeA r1;
Damper 1.5 flangeA r1;
Inertia 0.5 r1 flangeB
let DCMotor flange:Rotational -> Equations =
let e1:Electrical in
let e2:Electrical in
let e3:Electrical in
let e4:Electrical in
ConstantVoltage 60. e1 e4;
Resistor 100. e1 e2;
Inductor 0.2 e2 e3;
EMF 1. e3 e4 flange;
Ground e4
let FlexibleShaft n:Int -> flangeA:Rotational -> flangeB:Rotational ->
Equations =
if n == 1 then
ShaftElement flangeA flangeB
else
let r1:Rotational in
ShaftElement flangeA r1;
FlexibleShaft (n-1) r1 flangeB
D.11.1 MechSys
include MechsysBasics
include MechatronicElaboration
let MechSys =
let r1:Rotational in
let r2:Rotational in
let r3:Rotational in
DCMotor r1;
Inertia 0.2 r1 r2;
FlexibleShaft 40000 r2 r3
let main =
let (eqs,probes) = elaborate MechSys in
244
D MKL Library
print ("Unknowns: " ++ int2string (noUnknowns eqs) ++ "\n" ++
"Equations: " ++ int2string (noEquations eqs) ++ "\n")
D.11.2
CircuitHierarchy
include MechatronicElaboration
include ExportModelica
include AnalogElectrical
let SubComponent p:Electrical -> n:Electrical =
let e1:Electrical in
Resistor 150. p e1;
Inductor 0.1 e1 n;
Capacitor 0.01 e1 n
let RecComp lev:Int -> p:Electrical -> n:Electrical -> Equations =
let e1:Electrical in
if lev == 1 then SubComponent p n else
RecComp (lev-1) p e1;
RecComp (lev-1) e1 n;
RecComp (lev-1) e1 n
let Circuit =
let ee1:Electrical in
let ee2:Electrical in
SineVoltage 220. 50. ee1 ee2;
RecComp 11 ee1 ee2;
Ground ee2
let main =
let (eqs,probes) = elaborate Circuit in
print ("Unknowns: " ++ int2string (noUnknowns eqs) ++ "\n" ++
"Equations: " ++ int2string (noEquations eqs) ++ "\n")
Notation
Symbols and Operators
x
y
u
R
N
∀x
∃x
¬p
p∧q
p∨q
iff
x∈A
y∈
/A
A\B
A∪B
A∩B
L1 ⊕ L2
Γ
τ
e
State vector
Measurement signal
Known input signal
The set of real numbers
The set of natural numbers {0, 1, 2, 3, . . . }.
For all x (universal quantifier)
For some x (existential quantifier)
Negation of p
Conjunction of p and q
Disjunction of p and q
If and only if
Element x is a member of set A
Element x is not an element of set A
Difference of set A and set B
Union of set A and set B
Intersection of set A and set B
Appends list L2 to L1
Typing Environment
Type
Expression
Abbreviations and Acronyms
ADT
Abstract Data Types
245
246
AST
BNF
BTA
CBN
CBV
CPS
DAE
DSL
EBNF
FP
DSP
EOO
FHM
FRP
GADT
GUI
HDL
HOAM
JIT
MDA
MKL
MSL
ODE
OOP
PE
SUNDIALS
UML
YACC
Notation
Abstract Syntax Tree
Backus-Naur Form
Binding-Time Analysis
Call-by-name
Call-by-value
Cyber-Physical System
Differential-Algebraic Equation
Domain-Specific Language
Extended Backus-Naur Form
Functional Programming
Domain-Specific Processor
Equation-Based Object-Oriented
Functional Hybrid Modeling
Functional Reactive Programming
Generalized Algebraic Data Type
Graphical User Interface
Hardware Description Language
Higher-Order Acausal Models
Just-in-time
Model Driven Architecture
Modeling Kernel Language
Modelica Standard Library
Ordinary Differential Equation
Object-Oriented Programming
Partial Evaluation
SUite of Nonlinear and DIfferential/ALgebraic equation
Solvers
Unified Modeling Language
Yet Another Compiler Compiler
Bibliography
[1] Martín Abadi, Luca Cardelli, Benjamin Pierce, and Gordon Plotkin. Dynamic typing in a statically typed language. ACM Transactions on Programming Languages
and Systems, 13(2):237–268, 1991.
[2] Martín Abadi and Luca Cardelli. A Theory of Objects. Springer-Verlag, New York,
USA, 1996.
[3] Accellera Organization. Verilog-AMS Language Reference Manual - Analog &
Mixed-Signal Extensions to Verilog HDL Version 2.3.1, 2009. Available from:
http://www.vhdl.org/verilog-ams/ [Last accessed: July 30, 2010].
[4] Alfred V. Aho, Monica S. Lam, Ravi Sethi, and Jeffrey D. Ullman. Compilers:
Principles, Techniques, and Tools. Addison-Wesley, Boston, MA, USA, 2nd edition, 2006.
[5] Johan Åkesson, Karl-Erik Årzén, Magnus Gäfvert, Tove Bergdahl, and
Hubertus Tummescheit.
Modeling and Optimization with Optimica and
JModelica.org—Languages and Tools for Solving Large-Scale Dynamic Optimization Problem. Computers and Chemical Engineering, January 2010.
Doi:10.1016/j.compchemeng.2009.11.011.
[6] Mats Andersson. Object-Oriented Modeling and Simulation of Hybrid Systems.
PhD thesis, Department of Automatic Control, Lund Institute of Technology, Sweden, December 1994.
[7] Deborah J. Armstrong. The quarks of object-oriented development. Communications of the ACM, 49(2):123–128, 2006.
[8] Peter Aronsson and David Broman. Extendable Physical Unit Checking with Understandable Error Reporting. In Proceedings of the 7th International Modelica
Conference, pages 890–897, Como, Italy, 2009.
247
248
Bibliography
[9] Peter Aronsson, Peter Fritzson, Levon Saldamli, Peter Bunus, and Kaj Nyström.
Meta Programming and Function Overloading in OpenModelica. In Proceedings
of the 3rd International ModelicaConference, pages 431–440, Linköping, Sweden,
2003.
[10] Peter J. Ashenden, Gregory D. Peterson, and Darrell A. Teegarden. The System
Designer’s Guide to VHDL-AMS: Analog, Mixed-Signal, and Mixed-Technology
Modeling. Morgan Kaufmann Publishers, USA, 2002.
[11] Donald C. Augustin, Mark S. Fineberg, Bruce B. Johnson, Robert N. Linebarger,
F. John Sansom, and Jon C. Strauss. The SCi Continuous System Simulation Language (CSSL). SIMULATION, 9:281–303, 1967.
[12] Henk Barendregt. The Lambda Calculus: Its Syntax and Semantics. North Holland, revised edition, 1984.
[13] Paul Inigo Barton. The Modelling and Simulation of Combined Discrete/Continuous Processes. PhD thesis, Department of Chemical Engineering, Imperial Collage
of Science, Technology and Medicine, London, UK, 1992.
[14] Albert Benveniste and Gérard Berry. The Synchronous Approach to Reactive and
Real-Time Systems. Proceedings of the IEEE, 79(9):1270–1282, 1991.
[15] Per Bjesse, Koen Claessen, Mary Sheeran, and Satnam Singh. Lava: hardware
design in Haskell. In Proceedings of the third ACM SIGPLAN international conference on Functional programming, pages 174–184, New York, USA, 1998. ACM
Press.
[16] A.P.J. Breunese and J.F. Broenink. Modeling Mechatronic Systems Using the
SIDOPS+ Language. In Proceedings of ICBGM’97, 3rd International Conference
on Bond Graph Modeling and Simulation, volume 29 of Simulation Series, pages
301–306, 1997.
[17] David Broman. Flow Lambda Calculus for Declarative Physical Connection Semantics. Technical Reports in Computer and Information Science No. 1, LIU Electronic Press, 2007.
[18] David Broman. Safety, Security, and Semantic Aspects of Equation-Based ObjectOriented Languages and Environments. Licentiate thesis. Thesis No 1337. Department of Computer and Information Science, Linköping University, December
2007.
[19] David Broman. Growing an Equation-Based Object-Oriented Modeling Language.
In Proceedings of MATHMOD 09 Vienna, pages 1316–1324, Vienna, Austria,
2009.
[20] David Broman. Should Software Engineering Projects be the Backbone or the Tail
of Computing Curricula? In Proceedings of the 23th IEEE Conference on Software
Engineering Education and Training, pages 153–156, Pittsburgh, USA, 2010.
Bibliography
249
[21] David Broman, Peter Aronsson, and Peter Fritzson. Design Considerations for Dimensional Inference and Unit Consistency Checking in Modelica. In Proceedings
of the 6th International Modelica Conference, pages 3–12, Bielefeld, Germany,
2008.
[22] David Broman and Peter Fritzson. Type Safety of Equation-Based Object-Oriented
Modeling Languages. PLDI ’06: Poster session at the ACM SIGPLAN 2006 Conference on Programming Language Design and Implementation, Ottawa, Canada,
2006.
[23] David Broman and Peter Fritzson. Ideas for Security Assurance in Security Critical
Software using Modelica. In Proceedings of the Conference on Modeling and
Simulation for Public Safety, pages 45–54, Linköping, Sweden, 2005.
[24] David Broman and Peter Fritzson. Abstract Syntax Can Make the Definition of
Modelica Less Abstract. In Proceedings of the 1st International Workshop on
Equation-Based Object-Oriented Languages and Tools, pages 111–126, Berlin,
Germany, 2007. LIU Electronic Press.
[25] David Broman and Peter Fritzson. Higher-Order Acausal Models. In Proceedings
of the 2nd International Workshop on Equation-Based Object-Oriented Languages
and Tools, pages 59–69, Paphos, Cyprus, 2008. LIU Electronic Press.
[26] David Broman and Peter Fritzson. Higher-Order Acausal Models. Simulation
News Europe, 19(1):5–16, 2009.
[27] David Broman, Peter Fritzson, and Sébastien Furic. Types in the Modelica Language. In Proceedings of the Fifth International Modelica Conference, pages 303–
315, Vienna, Austria, 2006.
[28] David Broman, Kaj Nyström, and Peter Fritzson. Determining Over- and UnderConstrained Systems of Equations using Structural Constraint Delta. In Proceedings of the Fifth International Conference on Generative Programming and Component Engineering (GPCE’06), pages 151–160, Portland, Oregon, USA, 2006.
ACM Press.
[29] Peter Bunus and Peter Fritzson. Automated Static Analysis of Equation-Based
Components. SIMULATION, 80(7–8):321–245, 2004.
[30] Peter Bunus and Karin Lunde. Supporting Model-Based Diagnostics with
Equation-Based Object Oriented Languages. In Proceedings of the 2nd International Workshop on Equation-Based Object-Oriented Languages and Tools, pages
121–130, Paphos, Cyprus, 2008. LIU Electronic Press.
[31] Cristiano Calcagno, Walid Taha, Liwen Huang, and Xavier Leroy. Implementing Multi-stage Languages Using ASTs, Gensym, and Reflection. In Proceedings
of Second International Conference on Generative Programming and Component
Engineering (GPCE’03), volume 2830 of LNCS, pages 57–76. Springer-Verlag,
2003.
250
Bibliography
[32] Luca Cardelli. Type Systems. In The Computer Science and Engineering Handbook, chapter 97. CRC Press, second edition, 2004.
[33] Luca Cardelli and Peter Wegner. On Understanding Types, Data Abstraction, and
Polymorphism. ACM Comput. Surv., 17(4):471–523, 1985.
[34] Francesco Casella, Filippo Donida, and Marco Lovera. Beyond Simulation: Computer Aided Control System Design Using Equation-Based Object Oriented Modelling for the Next Decade. In Proceedings of the 2nd International Workshop
on Equation-Based Object-Oriented Languages and Tools, pages 35–45, Paphos,
Cyprus, 2008. LIU Electronic Press.
[35] François E. Cellier. Continuous System Modeling. Springer-Verlag, New York,
USA, 1991.
[36] François E. Cellier. Object-Oriented Modeling of Physical Systems: Promises
and Expectations. In Proc. Symposium on Modelling, Analysis, and Simulation,
CESA’96, IMACS MultiConference on Computational Engineering in Systems
Applications, pages 1126–1127, Lille, France, 1996.
[37] François E. Cellier and Ernesto Kofman. Continuous System Simulation. SpringerVerlag, New York, USA, 2006.
[38] François E. Cellier and Àngela Nebot. The Modelica Bond-Graph Library. In
Proceedings of the 4th International Modelica Conference, pages 57–65, Hamburg,
Germany, 2005.
[39] James Cheney and Hinze Ralf. First-Class Phantom Types. CISTR TR2003-1901,
Cornell University, 2003.
[40] Ernst Christen and Kenneth Bakalar. VHDL-AMS - A Hardware Description Language for Analog and Mixed-Signal Applications. IEEE Transactions on Circuits
and Systems II: Analog and Digital Signal Processing, 46(10):1263–1272, 1999.
[41] Koen Claessen. Embedded Languages for Describing and Verifying Hardware.
PhD thesis, Department of Computer Science, Chalmers University of Technology
and Göteborg University, Sweden, 2001.
[42] D. E. Comer, David Gries, Michael C. Mulder, Allen Tucker, A. Joe Turner, and
Paul R. Young. Computing as a discipline. Communications of the ACM, 32(1):9–
23, 1989.
[43] Krysztof Czarnecki and Ulrich Eisenecker. Generative Programming: Methods,
Tools, and Applications. Addison-Wesley, 2000.
[44] Ole-Johan Dahl and Kristen Nygaard. SIMULA: an ALGOL-based simulation
language. Communications of the ACM, 9(9):671–678, 1966.
[45] Dassault Systems. Multi-Engineering Modeling and Simulation - Dymola - CATIA - Dassault Systemes. http://www.dymola.com [Last accessed: July 14,
2010].
Bibliography
251
[46] Nikolas G. de Bruijn. Lambda Calculus Notations with Nameless Dummies, a
Tool For Automatic Formula Manipulation, with Application to the Church-Rosser
Theorem. "Indagationes Mathematicae", 34(5):381–392, 1972.
[47] Hilding Elmqvist. A Structured Model Language for Large Continuous Systems.
PhD thesis, Department of Automatic Control, Lund University, Sweden, May
1978.
[48] Hilding Elmqvist, Sven Erik Mattsson, and Martin Otter. Modelica - A Language
for Physical System Modeling, Visualization and Interaction. In Proceedings of the
IEEE International Symposium on Computer Aided Control System Design, 1999.
[49] Hilding Elmqvist and Martin Otter. Methods for Tearing Systems of Equations in
Object-Oriented Modelling. In Proceedings ESM’94 European Simulation Multiconference, pages 326–332, 1994.
[50] Thilo Ernst, Stephan Jähnichen, and Matthias Klose. The Architecture of the
Smile/M Simulation Environment. In Proceedings 15th IMACS World Congress on
Scientific Computation, Modelling and Applied Mathematics, volume 6 of Modelling and Applied Mathematics, pages 653–658, 1997.
[51] Peter Fritzson. Principles of Object-Oriented Modeling and Simulation with Modelica 2.1. Wiley-IEEE Press, New York, USA, 2004.
[52] Peter Fritzson, Peter Aronsson, Håkan Lundvall, Kaj Nyström, Adrian Pop, Levon
Saldamli, and David Broman. The OpenModelica Modeling, Simulation, and Development Environment. In Proceedings of the 46th Conference on Simulation and
Modeling (SIMS’05), pages 83–90, Trondheim, Norway, 2005.
[53] Peter Fritzson, Peter Aronsson, Adrian Pop, Håkan Lundvall, Kaj Nyström,
Levon Saldamli, David Broman, and Anders Sandholm. OpenModelica - A
Free Open-Source Environment for System Modeling, Simulation, and Teaching. In Proceedings of the 2006 IEEE Conference on Computer Aided Control
Systems Design, Munich, Germany, 2006. See also the OpenModelica Project.
www.openmodelica.org [Last accessed: Dec 30, 2008].
[54] Peter Fritzson, David Broman, François Cellier, and Christoph Nytsch-Geusen.
Equation-Based Object-Oriented Languages and Tools. Report on the Workshop
EOOLT 2007 at ECOOP 2007. In Object-Oriented Technology. ECOOP 2007
Workshop Reader, volume 4906 of LNCS, pages 27–39. Springer-Verlag, 2008.
[55] Peter Fritzson and Vadim Engelson. Modelica - A Unified Object-Oriented Language for System Modeling and Simulation. In Proceedings of the European
Conference on Object-Oriented Programming, volume 1445 of LNCS. SpringerVerlag, 1998.
[56] Peter Fritzson, Adrian Pop, and Peter Aronsson. Towards Comprehensive MetaModeling and Meta-Programming Capabilities in Modelica. In Proceedings of the
4th International Modelica Conference, pages 519–525, Hamburg, Germany, 2005.
252
Bibliography
[57] Peter Fritzson, Adrian Pop, David Broman, and Peter Aronsson. Formal Semantics
Based Translator Generation and Tool Development in Practice. In Proceedings of
ASWEC 2009 Australian Software Engineering Conference, pages 256–266. IEEE
Computer Society, 2009.
[58] Peter Fritzson, Lars Viklund, Johan Herber, and Dag Fritzson. High-level mathematical modeling and programming. IEEE Software, 12(4):77–87, 1995.
[59] Georgina Fábián. A Language and Simulator for Hybrid Systems. PhD thesis, Institute for Programming research and Algorithmics, Technische Universiteit Eindhoven, Netherlands, Netherlands, 1999.
[60] Walter Gellert. The VNR Concise Encyclopedia of Mathematics. Van Nostrand
Reinhold, 1977.
[61] George Giorgidze and Henrik Nilsson. Embedding a functional hybrid modelling
language in Haskell. In Proceedings of the 20th International Symposium on the
Implementation and Application of Functional Languages, 2008.
[62] George Giorgidze and Henrik Nilsson. Higher-Order Non-Causal Modelling and
Simulation of Structurally Dynamic Systems. In Proceedings of the 7th International Modelica Conference, pages 208–218, Como, Italy, September 2009. LIU
Electronic Press.
[63] George Giorgidze and Henrik Nilsson. Mixed-level Embedding and JIT Compilation for an Iteratively Staged DSL. In Proceedings of the 19th Workshop on Functional and (Constraint) Logic Programming (WFLP’10), pages 19–34, Madrid,
Spain, January 2010.
[64] Adele Goldberg and David Robson. Smalltalk-80: the language and its implementation. Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 1983.
[65] James Gosling, Bill Joy, Guy Steele, and Gilad Bracha. The Java Language Specification, 3rd Edition. Prentice Hall, 2005.
[66] Fritz Henglein. Efficient type inference for higher-order binding-time analysis. In
Functional Programming Languages and Computer Architecture, volume 523 of
LNCS, pages 448–472. Springer-Verlag, 1991.
[67] J. Roger Hindley and Jonathan P. Seldin. Lambda-Calculus and Combinators: An
Introduction. Cambridge University Press, 2nd edition, 2008.
[68] Alan C. Hindmarsh, Peter N. Brown, Keith E. Grant, Steven L. Lee, Radu Serban, Dan E. Shumaker, and Carol S. Woodward. SUNDIALS: Suite of nonlinear
and differential/algebraic equation solvers. ACM Transactions on Mathematical
Software, 31(3):363–396, 2005.
[69] Graham Hutton. Programming in Haskell. Cambridge University Press, 2007.
[70] Iain S. Duff. On Algorithms for Obtaining a Maximum Transversal. ACM Transactions on Mathematical Software, 7(3):315–330, 1981.
253
Bibliography
[71] Iain S. Duff and John K. Reid. An Implementation of Tarjan’s Algorithm for the
Block Triangularization of a Matrix. ACM Transactions on Mathematical Software, 4(2):137–147, 1978.
[72] IEEE 1706.1 Working Group. IEEE Std 1076.1-1999, IEEE Standard VHDL Analog and Mixed-Signal Extensions. IEEE Press, New York, USA, 1999.
[73] INRIA. Scicos Homepage. http://www-rocq.inria.fr/scicos/ [Last
accessed: July 10, 2010].
[74] INRIA. The Caml language: Home. http://caml.inria.fr/ [Last accessed: July 13, 2010].
[75] ISO/IEC. ISO/ IEC 14882 : Programming language C++. ANSI, New York, USA,
1998.
[76] ITI. SimulationX. http://www.iti.de/ [Last accessed: July 10, 2010].
[77] Barry Jay. Pattern Calculus: Computing with Functions and Structures. SpringerVerlag, 2009.
[78] JModelica.org.
2010].
http://www.jmodelica.org [Last accessed: July 10,
[79] Johan Åkesson. Languages and Tools for Optimization of Large-Scale Systems.
PhD thesis, Department of Automatic Control, Lund Institute of Technology, Sweden, November 2007.
[80] Gilles Kah. An experiment in partial evaluation: The generation of a compiler
generator. In Rewriting Techniques and Applications, volume 202 of LNCS, pages
124–140. Springer-Verlag, 1985.
[81] Gilles Kahn. Natural semantics. In 4th Annupal Symposium on Theoretical Aspects of Computer Sciences on STACS 87, volume 247 of LNCS, pages 22–39,
Passau, Germany, 1987. Springer-Verlag.
[82] Mattihias Kloas, Viktor Friesen, and Martin Simons. SMILE - A Simulation Environment for Energy System. In Proceedings of the 5th International IMACSSymposium on Systems Analysis and Simulation (SAS’95), pages 503–506. Gordon and Breach Publishers, 1995.
[83] Peter Kunkel and Volker Mehrmann. Differential-Algebraic Equations Analysis
and Numerical Solution. European Mathematical Society, 2006.
[84] David Kågedal. A Natural Semantics specification for the equation-based modeling
languge Modelica. Master’s thesis, Linköping University, 1998.
[85] David Kågedal and Peter Fritzson. Generating a Modelica Compiler from Natural
Semantics Specifications. In Proceedings of the Summer Computer Simulation
Conference, 1998.
254
Bibliography
[86] Chris Lattner and Vikram Adve. LLVM: A Compilation Framework for Lifelong
Program Analysis & Transformation. In Proceedings of the International Symposium on Code Generation and Optimization (CGO’04). IEEE Press, 2004.
[87] Edward A. Lee. Computing needs time. Communications of the ACM, 52(5):70–
79, 2009.
[88] Lennart Ljung. System Identification: Theory for the User. Prentice Hall, second
edition, 1999.
[89] LMS. LMS International - 1D and 3D simulation software, testing systems and
engineering services. http://www.lmsintl.com/ [Last accessed: July 10,
2010].
[90] Maplesoft. Math Software for Engineers, Educators & Students - Maplesoft.
http://www.maplesoft.com/ [Last accessed: July 10, 2010].
[91] MathCore.
MathModelica System Designer: Model based design of
multi-engineering systems.
http://www.mathcore.com/products/
mathmodelica/ [Last accessed: June 10, 2010].
[92] MathWorks. The Mathworks - Simulink - Simulation and Model-Based Design. http://www.mathworks.com/products/simulink/ [Last accessed: November 8, 2007].
[93] Sven Erik Mattsson, Hilding Elmqvist, Martin Otter, and Hans Olsson. Initialization of Hybrid Differential-Algebraic Equations in Modelica 2.0. In Proceedings
of the 2nd International Modelica Conference, pages 9–15, Oberpfaffenhofen, Germany, 2003.
[94] Sven Erik Mattsson and Gustaf Söderlind. Index reduction in differential-algebraic
equations using dummy derivatives. 14(3):677–692, 1993.
[95] Jakob Mauss. Modelica Instance Creation. In Proceedings of the 4th International
Modelica Conference, Hamburg, Germany, 2005.
[96] Joaquin Miller and Jishnu Mukerji. MDA Guide Version 1.0.1, 2003. Available
from: http://www.omg.org.
[97] Robin Milner. A Theory of Type Polymorphism in Programming. Journal of Computer and System Sciences, 17(3):348–375, 1978.
[98] Robin Milner, Mads Tofte, Robert Harper, and David MacQuee. The Definition of
Standard ML - Revised. The MIT Press, 1997.
[99] John C. Mitchell. Concepts in Programming Languages. Cambridge University
Press, 2003.
[100] Modelica Association. http://www.modelica.org. [Last accessed: July 10,
2010].
Bibliography
255
[101] Modelica Association. Modelica - A Unified Object-Oriented Language for Physical Systems Modeling - Version 1, September 1997. Available from: http:
//www.modelica.org.
[102] Modelica Association. Modelica - A Unified Object-Oriented Language for Physical Systems Modeling - Language Specification Version 2.2, February 2005. Available from: http://www.modelica.org.
[103] Modelica Association. Modelica - A Unified Object-Oriented Language for Physical Systems Modeling - Language Specification Version 3.0, 2007. Available from:
http://www.modelica.org.
[104] Modelica Association. Modelica - A Unified Object-Oriented Language for Physical Systems Modeling - Language Specification Version 3.2, 2010. Available from:
http://www.modelica.org.
[105] Modelica Association. Modelica Libraries - Modelica Portal, 2010. Available
from: http://www.modelica.org/libraries. [Last accessed: July 9,
2010].
[106] Masoud Najafi and Ramine Nikoukhah. Modeling and simulation of differential
equations in Scicos. In Proceedings of the Fifth International Modelica Conference,
pages 177–185, Vienna, Austria, 2006.
[107] IEEE Standards Information Network. IEEE 100 The Authoritative Dictionary of
IEEE Standards Terms. IEEE Press, New York, USA, 2000.
[108] Henrik Nilsson. Type-Based Structural Analysis for Modular Systems of Equations. In Proceedings of the 2nd International Workshop on Equation-Based
Object-Oriented Languages and Tools, pages 71–81, Paphos, Cyprus, 2008. LIU
Electronic Press.
[109] Henrik Nilsson, John Peterson, and Paul Hudak. Functional Hybrid Modeling. In
Practical Aspects of Declarative Languages : 5th International Symposium, PADL
2003, volume 2562 of LNCS, pages 376–390, New Orleans, Lousiana, USA, January 2003. Springer-Verlag.
[110] Henrik Nilsson, John Peterson, and Paul Hudak. Functional Hybrid Modeling from
an Object-Oriented Perspective. In Proceedings of the 1st International Workshop
on Equation-Based Object-Oriented Languages and Tools, pages 71–87, Berlin,
Germany, 2007. LIU Electronic Press.
[111] Kristoffer Norling, David Broman, Peter Fritzson, Alexander Siemers, and Dag
Fritzson. Secure Distributed Co-Simulation over Wide Area Networks. In Proceedings of the 48th Conference on Simulation and Modelling (SIMS 2007), pages
14–23, Göteborg (Särö), Sweden, 2007. LIU Electronic Press.
[112] Christoph Nytsch-Geusen et. al. MOSILAB: Development of a Modelica based
generic simulation tool supporting model structural dynamics. In Proceedings of
the 4th International Modelica Conference, Hamburg, Germany, 2005.
256
Bibliography
[113] Object Management Group. Unified Modeling Language: Infrastructure version
2.1.1, February 2007. Available from: http://www.omg.org.
[114] Object Management Group. Unified Modeling Language: Superstructure version
2.1.1, February 2007. Available from: http://www.omg.org.
[115] M. Oh and Costas C. Pantelides. A modelling and Simulation Language for Combined Lumped and Distributed Parameter Systems. Computers and Chemical Engineering, 20(6–7).
[116] Hans Olsson, Martin Otter, Sven Erik Mattsson, and Hilding Elmqvist. Balanced
Models in Modelica 3.0 for Increased Model Quality. In Proceedings of the 6th
International Modelica Conference, pages 21–33, Bielefeld, Germany, 2008.
[117] OpenModelica Project. http://www.openmodelica.org [Last accessed:
July 10, 2010].
[118] Constantinos C. Pantelides. The Consistent Initialization of Differential-Algebraic
Systems. SIAM Journal on Scientific and Statistical Computing, 9(2):213–231,
1988.
[119] Terence Parr. ANTLR Parser Generator. http://www.antlr.org/ [Last
accessed: November 8, 2007].
[120] Mikael Pettersson. Compiling Natural Semantics. PhD thesis, Department of Computer and Information Science, Linköping University, Sweden, 1995.
[121] Linda R. Petzold. A Description of DASSL: A Differential/Algebraic System
Solver. In IMACS Trans. on Scientific Comp., 10th IMACS World Congress on
Systems Simulation and Scientific Comp., Montreal, Canada, 1982.
[122] Simon Peyton Jones. The Implementation of Functional Programming Languages.
Prentice Hall, 1987.
[123] Simon Peyton Jones, Dimitrios Vytiniotis, Stephanie Weirich, and Geoffrey Washburn. Simple unification-based type inference for gadts. In Proceedings of the
eleventh ACM SIGPLAN international conference on Functional programming,
pages 50–61, New York, USA, 2006. ACM Press.
[124] Benjamin C. Pierce. Types and Programming Languages. The MIT Press, 2002.
[125] Rinus Plasmeijer and Marko van Eekelen. Concurrent CLEAN Language Report
- Version 2.1, 2002. Available from: http://clean.cs.ru.nl/. [Last accessed: July 13, 2010].
[126] Gordon D. Plotkin. A Structural Approach to Operational Semantics. Technical
report, Department of Computer Science, University of Aarhus, 1981.
[127] Adrian Pop. Integrated Model-Driven Development Environments for EquationBased Object-Oriented Languages. PhD thesis, Department of Computer and Information Science, Linköping University, Sweden, 2008.
Bibliography
257
[128] Per Sahlin and E.F. Sowell. A Neutral Format for Building Simulation Models.
In In Proceedings of the Conference on Building Simulation, IBPSA, Vancouver,
Canada, 1989.
[129] Tim Sheard. Accomplishments and research challenges in meta-programming. In
Proceedings of the Workshop on Semantics, Applications, and Implementation of
Program Generation, volume 2196 of LNCS, pages 2–44. Springer-Verlag, 2001.
[130] Tim Sheard and Simon Peyton Jones. Template Meta-programming for Haskell.
In Haskell ’02: Proceedings of the 2002 ACM SIGPLAN workshop on Haskell,
pages 1–16, New York, USA, 2002. ACM Press.
[131] Tim Sheard and Emir Pasalic. Meta-programming With Built-in Type Equality.
Electronic Notes in Theoretical Computer Science, 199:49–65, 2008.
[132] Jeremy Siek and Walid Taha. Gradual typing for functional languages. In In:
Scheme and Functional Programming Workshop, 2006.
[133] Jeremy Siek and Walid Taha. Gradual Typing for Objects. In Proceedings of
the 21st European conference on ECOOP 2007: Object-Oriented Programming,
volume 4609 of LNCS, pages 2–27. Springer-Verlag, 2007.
[134] Simon Peyton Jones. Haskell 98 Language and Libraries – The Revised Report.
Cambridge University Press, 2003.
[135] Alan Snyder. Encapsulation and Inheritance in Object-Oriented Programming Languages. In OOPLSA ’86: Conference proceedings on Object-oriented programming systems, languages and applications, pages 38–45, Portland, Oregon, United
States, 1986. ACM Press.
[136] Guy L. Steele. Growing a Language. Videotape (54 minutes) of a talk at the ACM
Conference on Object-Oriented Programming, Systems, Languages, and Applications, University Video Communications, 1998.
[137] Guy L. Steele. Common LISP. The Language. Digital Press, 2nd edition, 1990.
[138] Guy L. Steele. Growing a Language. Higher-Order and Symbolic Computation,
12:221–236, 1999.
[139] Bjarne Stroustrup. A history of C++ 1979–1991. In HOPL-II: The second ACM
SIGPLAN conference on History of programming languages, pages 271–297, New
York, USA, 1993. ACM Press.
[140] Walid Taha. Multi-Stage Programming: Its Theory and Applications. PhD thesis,
Oregon Graduate Institute of Science and Technology, Oregon, USA, November
1999.
[141] Walid Taha. A Gentle Introduction to Multi-stage Programming. In DomainSpecific Program Generation, volume 3016 of LNCS, pages 30–50. SpringerVerlag, 2004.
258
Bibliography
[142] Walid Taha et al. MetaOCaml Homepage. http://www.metaocaml.org/
[Last accessed: April 8, 2010].
[143] Walid Taha and Tim Sheard. Multi-stage programming with explicit annotations.
In PEPM ’97: Proceedings of the 1997 ACM SIGPLAN symposium on Partial
evaluation and semantics-based program manipulation, pages 203–217, New York,
USA, 1997. ACM Press.
[144] Walid Taha and Tim Sheard. MetaML and multi-stage programming with explicit
annotations. Theoretical Computer Science, 248(1–2):211–242, 2000.
[145] D.A. van Beek, A.T. Hofkamp, M.A. Reniers, J.E.Rooda, and R.R.H.Schiffelers.
Syntax and Formal Semantics of Chi 2.0. SE Report: Nr. 2008-01, Department of
Mechanical Engineering, Eindhoven University of Technology, 2008.
[146] D.A. van Beek, K.L. Man, MA. Reniers, J.e. Rooda, and R.R.H Schiffelers. Syntax and consistent equation semantics of hybrid Chi. The Journal of Logic and
Algebraic Programming, 68:129–210, 2006.
[147] Arie van Deursen and Paul Klint. Little Languages: Little Maintenance? Journal
of Software Maintenance: Research and Practice, 10(2):75–92, 1998.
[148] Arie van Deursen, Paul Klint, and Joost Visser. Domain-specific languages: an
annotated bibliography. ACM SIGPLAN Notices, 35(6):26–36, 2000.
[149] Philip Wadler. Comprehending monads. Mathematical Structures in Computer
Science, 2(4):461–493, 1992.
[150] Zhanyong Wan and Paul Hudak. Functional reactive programming from first principles. In PLDI ’00: Proceedings of the ACM SIGPLAN 2000 conference on Programming language design and implementation, pages 242–252, New York, USA,
2000. ACM Press.
[151] Andrew K. Wright and Matthias Felleisen. A Syntactic Approach to Type Soundness. Information and Computation, 115(1):38–94, 1994.
[152] Hongwei Xi, Chiyan Chen, and Gang Chen. Guarded recursive datatype constructors. In Proceedings of the 30th ACM SIGPLAN-SIGACT symposium on Principles of programming languages, pages 224–235, New York, USA, 2003. ACM
Press.
[153] Yun Zhu, Edwin Westbrook, Jun Inoue, Alexandre Chapoutot, Cherif Salama,
Marisa Peralta, Travis Martin, Walid Taha, Marcia O’Malley, Robert Cartwright,
Aaron Ames, and Raktim Bhattacharya. Mathematical equations as executable
models of mechanical systems. In Proceedings of the 1st ACM/IEEE International
Conference on Cyber-Physical Systems, pages 1–11, New York, USA, 2010. ACM
Press.
[154] Dirk Zimmer. Introducing Sol: A General Methodology for Equation-Based Modeling of Variable-Structure Systems. In Proceedings of the 6th International Modelica Conference, pages 47–56, Bielefeld, Germany, 2008.
Index
259
[155] Dirk Zimmer. Equation-Based Modeling of Variable-Structure Systems. PhD thesis, Swiss Federal Institute of Technology, Zürich, Switzerland, 2010.
Index
A
Abstract data type, 104, 225
Abstract syntax, 221
Abstract syntax tree, 29
Acausality, 9
Acumen, 205
Acusal
model, 111
ADT
Array, 225
Map, 226
Set, 226
Any model type, 133, 139
Array, 225
AST, 29
Component, 9
Conclusions, 211
Connection semantics, 11, 161
Connector, 27, 162
inside, 86
outside, 86
Conservation of energy, 11
Constrained
over, 76
under, 76
Constraint delta effect, 81
Contributions, 16
origin, 20
overview, 16
CSSL, 7
B
Balanced models, 206
Binding-time analysis, 128
Bot type, 151
D
DAE, 5
DAESolver, 228
hybrid, 29
DAESolver, 228
Debugging, 90
Depth-first search, 86
Diagnosis, 9
Differential-algebraic equation, 5
Discrete event-based, 7
Domain expert, 8
Domain-specific langauge, 8
C
Call-by-name, 97
Call-by-need, 97
Cast insertion, 144
Class, 26
Class type, 69
Coercion, 64
260
261
Index
DSL, 8
domain, 8
domain expert, 8
Dynamic dispatch, 66
E
Eager evaluation, 97
Elaboration, 11, 159
ElectricalBranch, 113
EOO, 6
origin, 7
EOO Model, 9
Equality, 152
Equation
modification, 28
Equation-based object-oriented, 6
Error, 12
detect, 14
Error detection, 90
Errors
untrapped, 56
Evaluation, 191
Eager, 97
Executable specification, 173
Experiment, 2
Export DAE, 186
Expressiveness, 14, 193
Extended backus-naur form, 69
Extensibility, 14, 193
Extensional metaprogramming, 214
F
Failure, 12
Fault, 12
Featherweight Modelica, 77
FHM, 204
File includer, 184
Functional programming, 96
Future work, 214
G
GADT, 208
General-purpose language, 8
gPROMS, 1, 7, 203
Gradual typing, 207
Graphical user interface, 30
GUI, 30
H
Hardware description language, 1, 7
HDL, 1, 7
Hierarchy naming, 177
Higher-order acausal model, 115
Higher-order acausal models, 109
Higher-order function, 97, 99
HOAM, 115
Hybrid Chi, 203
Hybrid DAE, 29
Hydra, 204
I
Implementation, 183
Information hiding, 64
Inheritane
private, 60
Initial conditions, 3
Initial value problem, 3
Inside connector, 86
Isolate error, 14
L
Lemma
Canonical forms, 149
inversion, 149
progress, 149
substitution, 150
Little languages, 8
M
Map, 226
Match, 102
Mathematical model, 2
MetaOcaml, 209
MKL, 16
core, 137
dynamic semantics, 146
lexical structure, 217
reserved keywords, 218
Simulation, 187
type safety, 148
type system, 139
Modeification equation, 28
Model, 2
destructing, 147
recursive, 117
262
Model application, 147
Model driven architecture, 2
Model lifting, 143
Model lifting relation, 141
Model type, 126
any, 139
specific, 139
Model value, 147
Modelica, 25, 26, 201, 206
compilation process, 29
connect, 27
featherweight, 77
modeling, 26
MSL, 25
process, 29
subtyping, 79
type equivalence, 78
types, 55, 206
Modelica standard library, 25
Modeling, 6
Modeling kernel language, 16
Module, 105
MSL, 25
Multi-domain modeling, 8
N
Natural Semantics, 205
Natural semantics, 34
Node, 112
O
Object, 8
Object type, 69
Object-oriented programming, 8
ODE, 2
Omola, 9
Optimization, 14
Outside connector, 86
Over-constrained, 76
Overloading, 64
P
Pantelides, 12, 30
Parametric polymorphism, 103
Partial application, 98
Partial differential equations, 9
Pattern matching, 102
Index
Pattern variable, 102
Performance aspects, 195
Polymorphism
parametric, 65
Port, 9
Preservation, 150
Probing, 177
Problem area, 12
Pseudo type, 132, 222
Published papers, 18
Pure language, 96
R
Recursion, 99
Recursive model, 117
Redeclare, 28
Related work, 201
Research method, 21
Research questions, 14
Restriction operator, 140
S
Safe substitution, 80
Safety aspects, 12
Scope, 16
Separate compilation, 76
Set, 226
Side effect, 96
Simulation, 5
reasons, 6
Simulink, 7
Sol, 204
Specific model type, 139
State-space form, 2
Statically typed, 97
Strict evaluation, 97
Strongly typed, 57
Structural constraint delta, 75, 80
Structural dynamic systems, 214
Structural type system, 78
Subtyping, 58, 79
Symbol table, 184
System, 2
System modeling error, 13
T
TempResistor, 28
Index
Thesis
future work, 214
problem area, 12
related work, 201
research method, 21
research questions, 14
scope, 16
Top-level, 98
Tuples, 101
TwoPin, 28
Type
any model, 133
model, 126
Type consistency, 140
Type equivalence, 78
Type inference, 65
Type safety, 57, 148
Type system, 57
nominal, 61
structural, 61
Types
prefixes, 71
Typing environment, 141
U
Under-constrained, 76
Unified modeling language, 2
Unit type, 101
Unknown, 126, 127
Unknowns, 147
Uses of models, 186
V
Verification, 189
VHDL-AMS, 1, 7, 202
263
Department of Computer and Information Science
Linköpings universitet
Dissertations
Linköping Studies in Science and Technology
No 14
Anders Haraldsson: A Program Manipulation
System Based on Partial Evaluation, 1977, ISBN 917372-144-1.
No 17
Bengt Magnhagen: Probability Based Verification
of Time Margins in Digital Designs, 1977, ISBN 917372-157-3.
No 18
No 22
No 33
No 51
No 54
No 55
No 58
No 69
No 71
No 77
No 94
No 97
No 109
No 111
No 155
No 165
No 170
No 174
No 192
No 213
No 214
No 221
No 239
Mats Cedwall: Semantisk analys av processbeskrivningar i naturligt språk, 1977, ISBN 91- 7372168-9.
Jaak Urmi: A Machine Independent LISP Compiler
and its Implications for Ideal Hardware, 1978, ISBN
91-7372-188-3.
Tore Risch: Compilation of Multiple File Queries in
a Meta-Database System 1978, ISBN 91- 7372-232-4.
Erland Jungert: Synthesizing Database Structures
from a User Oriented Data Model, 1980, ISBN 917372-387-8.
Sture Hägglund: Contributions to the Development
of Methods and Tools for Interactive Design of
Applications Software, 1980, ISBN 91-7372-404-1.
Pär Emanuelson: Performance Enhancement in a
Well-Structured Pattern Matcher through Partial
Evaluation, 1980, ISBN 91-7372-403-3.
Bengt Johnsson, Bertil Andersson: The HumanComputer Interface in Commercial Systems, 1981,
ISBN 91-7372-414-9.
H. Jan Komorowski: A Specification of an Abstract
Prolog Machine and its Application to Partial
Evaluation, 1981, ISBN 91-7372-479-3.
René Reboh: Knowledge Engineering Techniques
and Tools for Expert Systems, 1981, ISBN 91-7372489-0.
Östen Oskarsson: Mechanisms of Modifiability in
large Software Systems, 1982, ISBN 91- 7372-527-7.
Hans Lunell: Code Generator Writing Systems, 1983,
ISBN 91-7372-652-4.
Andrzej Lingas: Advances in Minimum Weight
Triangulation, 1983, ISBN 91-7372-660-5.
Peter Fritzson: Towards a Distributed Programming
Environment based on Incremental Compilation,
1984, ISBN 91-7372-801-2.
Erik Tengvald: The Design of Expert Planning
Systems. An Experimental Operations Planning
System for Turning, 1984, ISBN 91-7372- 805-5.
Christos Levcopoulos: Heuristics for Minimum
Decompositions of Polygons, 1987, ISBN 91-7870133-3.
James W. Goodwin: A Theory and System for NonMonotonic Reasoning, 1987, ISBN 91-7870-183-X.
Zebo Peng: A Formal Methodology for Automated
Synthesis of VLSI Systems, 1987, ISBN 91-7870-225-9.
Johan Fagerström: A Paradigm and System for
Design of Distributed Systems, 1988, ISBN 91-7870301-8.
Dimiter Driankov: Towards a Many Valued Logic of
Quantified Belief, 1988, ISBN 91-7870-374-3.
Lin Padgham: Non-Monotonic Inheritance for an
Object Oriented Knowledge Base, 1989, ISBN 917870-485-5.
No 244
No 252
No 258
No 260
No 264
No 265
No 270
No 273
No 276
No 277
No 281
No 292
No 297
No 302
No 312
No 338
No 371
No 375
No 383
Tony Larsson: A Formal Hardware Description and
Verification Method, 1989, ISBN 91-7870-517-7.
Michael Reinfrank: Fundamentals and Logical
Foundations of Truth Maintenance, 1989, ISBN 917870-546-0.
Jonas Löwgren: Knowledge-Based Design Support
and Discourse Management in User Interface
Management Systems, 1991, ISBN 91-7870-720-X.
Henrik Eriksson: Meta-Tool Support for Knowledge
Acquisition, 1991, ISBN 91-7870-746-3.
Peter Eklund: An Epistemic Approach to Interactive
Design in Multiple Inheritance Hierarchies, 1991,
ISBN 91-7870-784-6.
Patrick Doherty: NML3 - A Non-Monotonic
Formalism with Explicit Defaults, 1991, ISBN 917870-816-8.
Nahid
Shahmehri:
Generalized
Algorithmic
Debugging, 1991, ISBN 91-7870-828-1.
Nils Dahlbäck: Representation of DiscourseCognitive and Computational Aspects, 1992, ISBN
91-7870-850-8.
Ulf Nilsson: Abstract Interpretations and Abstract
Machines: Contributions to a Methodology for the
Implementation of Logic Programs, 1992, ISBN 917870-858-3.
Ralph Rönnquist: Theory and Practice of Tensebound Object References, 1992, ISBN 91-7870-873-7.
Björn Fjellborg: Pipeline Extraction for VLSI Data
Path Synthesis, 1992, ISBN 91-7870-880-X.
Staffan Bonnier: A Formal Basis for Horn Clause
Logic with External Polymorphic Functions, 1992,
ISBN 91-7870-896-6.
Kristian Sandahl: Developing Knowledge Management Systems with an Active Expert Methodology,
1992, ISBN 91-7870-897-4.
Christer Bäckström: Computational Complexity of
Reasoning about Plans, 1992, ISBN 91-7870-979-2.
Mats Wirén: Studies in Incremental Natural
Language Analysis, 1992, ISBN 91-7871-027-8.
Mariam Kamkar: Interprocedural Dynamic Slicing
with Applications to Debugging and Testing, 1993,
ISBN 91-7871-065-0.
Tingting Zhang: A Study in Diagnosis Using
Classification and Defaults, 1993, ISBN 91-7871-078-2
Arne Jönsson: Dialogue Management for Natural
Language Interfaces - An Empirical Approach, 1993,
ISBN 91-7871-110-X.
Simin Nadjm-Tehrani: Reactive Systems in Physical
Environments: Compositional Modelling and Framework for Verification, 1994, ISBN 91-7871-237-8.
Bengt Savén: Business Models for Decision Support
and Learning. A Study of Discrete-Event
Manufacturing Simulation at Asea/ABB 1968-1993,
1995, ISBN 91-7871-494-X.
Ulf Söderman: Conceptual Modelling of Mode
Switching Physical Systems, 1995, ISBN 91-7871-5164.
Andreas Kågedal: Exploiting Groundness in Logic
Programs, 1995, ISBN 91-7871-538-5.
No 396
No 413
No 414
No 416
No 429
No 431
No 437
No 439
No 448
No 452
No 459
No 461
No 462
No 475
No 480
No 485
No 494
No 495
No 498
No 502
No 503
No 512
No 520
No 522
George Fodor: Ontological Control, Description,
Identification and Recovery from Problematic
Control Situations, 1995, ISBN 91-7871-603-9.
Mikael Pettersson: Compiling Natural Semantics,
1995, ISBN 91-7871-641-1.
Xinli Gu: RT Level Testability Improvement by
Testability Analysis and Transformations, 1996, ISBN
91-7871-654-3.
Hua Shu: Distributed Default Reasoning, 1996, ISBN
91-7871-665-9.
Jaime Villegas: Simulation Supported Industrial
Training from
an
Organisational
Learning
Perspective - Development and Evaluation of the
SSIT Method, 1996, ISBN 91-7871-700-0.
Peter Jonsson: Studies in Action Planning:
Algorithms and Complexity, 1996, ISBN 91-7871-7043.
Johan
Boye:
Directional Types
in Logic
Programming, 1996, ISBN 91-7871-725-6.
Cecilia Sjöberg: Activities, Voices and Arenas:
Participatory Design in Practice, 1996, ISBN 91-7871728-0.
Patrick Lambrix: Part-Whole Reasoning in
Description Logics, 1996, ISBN 91-7871-820-1.
Kjell Orsborn: On Extensible and Object-Relational
Database Technology for Finite Element Analysis
Applications, 1996, ISBN 91-7871-827-9.
Olof Johansson: Development Environments for
Complex Product Models, 1996, ISBN 91-7871-855-4.
Lena Strömbäck: User-Defined Constructions in
Unification-Based Formalisms, 1997, ISBN 91-7871857-0.
Lars Degerstedt: Tabulation-based Logic Programming: A Multi-Level View of Query Answering,
1996, ISBN 91-7871-858-9.
Fredrik Nilsson: Strategi och ekonomisk styrning En studie av hur ekonomiska styrsystem utformas
och används efter företagsförvärv, 1997, ISBN 917871-914-3.
Mikael Lindvall: An Empirical Study of Requirements-Driven Impact Analysis in Object-Oriented
Software Evolution, 1997, ISBN 91-7871-927-5.
Göran Forslund: Opinion-Based Systems: The Cooperative Perspective on Knowledge-Based Decision
Support, 1997, ISBN 91-7871-938-0.
Martin Sköld: Active Database Management
Systems for Monitoring and Control, 1997, ISBN 917219-002-7.
Hans Olsén: Automatic Verification of Petri Nets in
a CLP framework, 1997, ISBN 91-7219-011-6.
Thomas Drakengren: Algorithms and Complexity
for Temporal and Spatial Formalisms, 1997, ISBN 917219-019-1.
Jakob Axelsson: Analysis and Synthesis of Heterogeneous Real-Time Systems, 1997, ISBN 91-7219-035-3.
Johan Ringström: Compiler Generation for DataParallel Programming Languages from Two-Level
Semantics Specifications, 1997, ISBN 91-7219-045-0.
Anna Moberg: Närhet och distans - Studier av kommunikationsmönster i satellitkontor och flexibla
kontor, 1997, ISBN 91-7219-119-8.
Mikael Ronström: Design and Modelling of a
Parallel Data Server for Telecom Applications, 1998,
ISBN 91-7219-169-4.
Niclas Ohlsson: Towards Effective Fault Prevention
- An Empirical Study in Software Engineering, 1998,
ISBN 91-7219-176-7.
No 526
No 530
No 555
No 561
No 563
No 567
No 582
No 589
No 592
No 593
No 594
No 595
No 596
No 597
No 598
No 607
No 611
No 613
No 618
No 627
No 637
No 639
Joachim Karlsson: A Systematic Approach for
Prioritizing Software Requirements, 1998, ISBN 917219-184-8.
Henrik Nilsson: Declarative Debugging for Lazy
Functional Languages, 1998, ISBN 91-7219-197-x.
Jonas Hallberg: Timing Issues in High-Level Synthesis, 1998, ISBN 91-7219-369-7.
Ling Lin: Management of 1-D Sequence Data - From
Discrete to Continuous, 1999, ISBN 91-7219-402-2.
Eva L Ragnemalm: Student Modelling based on Collaborative Dialogue with a Learning Companion,
1999, ISBN 91-7219-412-X.
Jörgen Lindström: Does Distance matter? On geographical dispersion in organisations, 1999, ISBN 917219-439-1.
Vanja Josifovski: Design, Implementation and
Evaluation of a Distributed Mediator System for
Data Integration, 1999, ISBN 91-7219-482-0.
Rita Kovordányi: Modeling and Simulating
Inhibitory
Mechanisms
in
Mental
Image
Reinterpretation - Towards Cooperative HumanComputer Creativity, 1999, ISBN 91-7219-506-1.
Mikael Ericsson: Supporting the Use of Design
Knowledge - An Assessment of Commenting
Agents, 1999, ISBN 91-7219-532-0.
Lars Karlsson: Actions, Interactions and Narratives,
1999, ISBN 91-7219-534-7.
C. G. Mikael Johansson: Social and Organizational
Aspects of Requirements Engineering Methods - A
practice-oriented approach, 1999, ISBN 91-7219-541X.
Jörgen Hansson: Value-Driven Multi-Class Overload
Management in Real-Time Database Systems, 1999,
ISBN 91-7219-542-8.
Niklas Hallberg: Incorporating User Values in the
Design of Information Systems and Services in the
Public Sector: A Methods Approach, 1999, ISBN 917219-543-6.
Vivian Vimarlund: An Economic Perspective on the
Analysis of Impacts of Information Technology:
From Case Studies in Health-Care towards General
Models and Theories, 1999, ISBN 91-7219-544-4.
Johan Jenvald: Methods and Tools in ComputerSupported Taskforce Training, 1999, ISBN 91-7219547-9.
Magnus Merkel: Understanding and enhancing
translation by parallel text processing, 1999, ISBN 917219-614-9.
Silvia Coradeschi: Anchoring symbols to sensory
data, 1999, ISBN 91-7219-623-8.
Man Lin: Analysis and Synthesis of Reactive
Systems:
A
Generic
Layered
Architecture
Perspective, 1999, ISBN 91-7219-630-0.
Jimmy Tjäder: Systemimplementering i praktiken En studie av logiker i fyra projekt, 1999, ISBN 917219-657-2.
Vadim Engelson: Tools for Design, Interactive
Simulation, and Visualization of Object-Oriented
Models in Scientific Computing, 2000, ISBN 91-7219709-9.
Esa Falkenroth: Database Technology for Control
and Simulation, 2000, ISBN 91-7219-766-8.
Per-Arne Persson: Bringing Power and Knowledge
Together: Information Systems Design for Autonomy
and Control in Command Work, 2000, ISBN 91-7219796-X.
No 660
No 688
No 689
No 720
No 724
No 725
No 726
No 732
No 745
No 746
No 757
No 747
No 749
No 765
No 771
No 772
No 758
No 774
No 779
No 793
No 785
No 800
No 808
No 821
Erik Larsson: An Integrated System-Level Design for
Testability Methodology, 2000, ISBN 91-7219-890-7.
Marcus
Bjäreland:
Model-based
Execution
Monitoring, 2001, ISBN 91-7373-016-5.
Joakim Gustafsson: Extending Temporal Action
Logic, 2001, ISBN 91-7373-017-3.
Carl-Johan Petri: Organizational Information Provision - Managing Mandatory and Discretionary Use
of Information Technology, 2001, ISBN-91-7373-1269.
Paul Scerri: Designing Agents for Systems with Adjustable Autonomy, 2001, ISBN 91 7373 207 9.
Tim Heyer: Semantic Inspection of Software
Artifacts: From Theory to Practice, 2001, ISBN 91
7373 208 7.
Pär Carlshamre: A Usability Perspective on Requirements Engineering - From Methodology to Product
Development, 2001, ISBN 91 7373 212 5.
Juha Takkinen: From Information Management to
Task Management in Electronic Mail, 2002, ISBN 91
7373 258 3.
Johan Åberg: Live Help Systems: An Approach to
Intelligent Help for Web Information Systems, 2002,
ISBN 91-7373-311-3.
Rego Granlund: Monitoring Distributed Teamwork
Training, 2002, ISBN 91-7373-312-1.
Henrik André-Jönsson: Indexing Strategies for Time
Series Data, 2002, ISBN 917373-346-6.
Anneli Hagdahl: Development of IT-supported
Interorganisational Collaboration - A Case Study in
the Swedish Public Sector, 2002, ISBN 91-7373-314-8.
Sofie Pilemalm: Information Technology for NonProfit Organisations - Extended Participatory Design
of an Information System for Trade Union Shop
Stewards, 2002, ISBN 91-7373-318-0.
Stefan Holmlid: Adapting users: Towards a theory
of use quality, 2002, ISBN 91-7373-397-0.
Magnus Morin: Multimedia Representations of Distributed Tactical Operations, 2002, ISBN 91-7373-4217.
Pawel Pietrzak: A Type-Based Framework for Locating Errors in Constraint Logic Programs, 2002, ISBN
91-7373-422-5.
Erik Berglund: Library Communication Among Programmers Worldwide, 2002, ISBN 91-7373-349-0.
Choong-ho Yi: Modelling Object-Oriented Dynamic
Systems Using a Logic-Based Framework, 2002, ISBN
91-7373-424-1.
Mathias Broxvall: A Study in the Computational
Complexity of Temporal Reasoning, 2002, ISBN 917373-440-3.
Asmus Pandikow: A Generic Principle for Enabling
Interoperability of Structured and Object-Oriented
Analysis and Design Tools, 2002, ISBN 91-7373-479-9.
Lars Hult: Publika Informationstjänster. En studie av
den Internetbaserade encyklopedins bruksegenskaper, 2003, ISBN 91-7373-461-6.
Lars Taxén: A Framework for the Coordination of
Complex Systems´ Development, 2003, ISBN 917373-604-X
Klas Gäre: Tre perspektiv på förväntningar och
förändringar i samband med införande av
informationssystem, 2003, ISBN 91-7373-618-X.
Mikael
Kindborg:
Concurrent
Comics
programming of social agents by children, 2003,
ISBN 91-7373-651-1.
No 823
No 828
No 833
No 852
No 867
No 872
No 869
No 870
No 874
No 873
No 876
No 883
No 882
No 887
No 889
No 893
No 910
No 918
No 900
No 920
No 929
No 933
Christina
Ölvingson:
On
Development
of
Information Systems with GIS Functionality in
Public Health Informatics: A Requirements
Engineering Approach, 2003, ISBN 91-7373-656-2.
Tobias Ritzau: Memory Efficient Hard Real-Time
Garbage Collection, 2003, ISBN 91-7373-666-X.
Paul
Pop:
Analysis
and
Synthesis
of
Communication-Intensive Heterogeneous Real-Time
Systems, 2003, ISBN 91-7373-683-X.
Johan Moe: Observing the Dynamic Behaviour of
Large Distributed Systems to Improve Development
and Testing – An Empirical Study in Software
Engineering, 2003, ISBN 91-7373-779-8.
Erik Herzog: An Approach to Systems Engineering
Tool Data Representation and Exchange, 2004, ISBN
91-7373-929-4.
Aseel Berglund: Augmenting the Remote Control:
Studies in Complex Information Navigation for
Digital TV, 2004, ISBN 91-7373-940-5.
Jo Skåmedal: Telecommuting’s Implications on
Travel and Travel Patterns, 2004, ISBN 91-7373-935-9.
Linda Askenäs: The Roles of IT - Studies of
Organising when Implementing and Using
Enterprise Systems, 2004, ISBN 91-7373-936-7.
Annika Flycht-Eriksson: Design and Use of Ontologies in Information-Providing Dialogue Systems,
2004, ISBN 91-7373-947-2.
Peter Bunus: Debugging Techniques for EquationBased Languages, 2004, ISBN 91-7373-941-3.
Jonas Mellin: Resource-Predictable and Efficient
Monitoring of Events, 2004, ISBN 91-7373-956-1.
Magnus Bång: Computing at the Speed of Paper:
Ubiquitous Computing Environments for Healthcare
Professionals, 2004, ISBN 91-7373-971-5
Robert Eklund: Disfluency in Swedish humanhuman and human-machine travel booking dialogues, 2004, ISBN 91-7373-966-9.
Anders Lindström: English and other Foreign
Linguistic Elements in Spoken Swedish. Studies of
Productive Processes and their Modelling using
Finite-State Tools, 2004, ISBN 91-7373-981-2.
Zhiping Wang: Capacity-Constrained Production-inventory systems - Modelling and Analysis in both a
traditional and an e-business context, 2004, ISBN 9185295-08-6.
Pernilla Qvarfordt: Eyes on Multimodal Interaction,
2004, ISBN 91-85295-30-2.
Magnus Kald: In the Borderland between Strategy
and Management Control - Theoretical Framework
and Empirical Evidence, 2004, ISBN 91-85295-82-5.
Jonas Lundberg: Shaping Electronic News: Genre
Perspectives on Interaction Design, 2004, ISBN 9185297-14-3.
Mattias Arvola: Shades of use: The dynamics of
interaction design for sociable use, 2004, ISBN 9185295-42-6.
Luis Alejandro Cortés: Verification and Scheduling
Techniques for Real-Time Embedded Systems, 2004,
ISBN 91-85297-21-6.
Diana Szentivanyi: Performance Studies of FaultTolerant Middleware, 2005, ISBN 91-85297-58-5.
Mikael Cäker: Management Accounting as
Constructing and Opposing Customer Focus: Three
Case Studies on Management Accounting and
Customer Relations, 2005, ISBN 91-85297-64-X.
No 937
No 938
No 945
No 946
No 947
No 963
No 972
No 974
No 979
No 983
No 986
No 1004
No 1005
No 1008
No 1009
No 1013
No 1016
No 1017
No 1018
No 1019
No 1021
No 1022
No 1030
No 1034
Jonas Kvarnström: TALplanner and Other
Extensions to Temporal Action Logic, 2005, ISBN 9185297-75-5.
Bourhane Kadmiry: Fuzzy Gain-Scheduled Visual
Servoing for Unmanned Helicopter, 2005, ISBN 9185297-76-3.
Gert Jervan: Hybrid Built-In Self-Test and Test
Generation Techniques for Digital Systems, 2005,
ISBN: 91-85297-97-6.
Anders Arpteg: Intelligent Semi-Structured Information Extraction, 2005, ISBN 91-85297-98-4.
Ola Angelsmark: Constructing Algorithms for Constraint Satisfaction and Related Problems - Methods
and Applications, 2005, ISBN 91-85297-99-2.
Calin Curescu: Utility-based Optimisation of
Resource Allocation for Wireless Networks, 2005,
ISBN 91-85457-07-8.
Björn Johansson: Joint Control in Dynamic
Situations, 2005, ISBN 91-85457-31-0.
Dan Lawesson: An Approach to Diagnosability
Analysis for Interacting Finite State Systems, 2005,
ISBN 91-85457-39-6.
Claudiu Duma: Security and Trust Mechanisms for
Groups in Distributed Services, 2005, ISBN 91-8545754-X.
Sorin Manolache: Analysis and Optimisation of
Real-Time Systems with Stochastic Behaviour, 2005,
ISBN 91-85457-60-4.
Yuxiao
Zhao:
Standards-Based
Application
Integration
for
Business-to-Business
Communications, 2005, ISBN 91-85457-66-3.
Patrik
Haslum:
Admissible
Heuristics
for
Automated Planning, 2006, ISBN 91-85497-28-2.
Aleksandra Tešanovic: Developing Reusable and
Reconfigurable Real-Time Software using Aspects
and Components, 2006, ISBN 91-85497-29-0.
David Dinka: Role, Identity and Work: Extending
the design and development agenda, 2006, ISBN 9185497-42-8.
Iakov Nakhimovski: Contributions to the Modeling
and Simulation of Mechanical Systems with Detailed
Contact Analysis, 2006, ISBN 91-85497-43-X.
Wilhelm Dahllöf: Exact Algorithms for Exact
Satisfiability Problems, 2006, ISBN 91-85523-97-6.
Levon Saldamli: PDEModelica - A High-Level Language for Modeling with Partial Differential Equations, 2006, ISBN 91-85523-84-4.
Daniel Karlsson: Verification of Component-based
Embedded System Designs, 2006, ISBN 91-85523-79-8
Ioan Chisalita: Communication and Networking
Techniques for Traffic Safety Systems, 2006, ISBN 9185523-77-1.
Tarja Susi: The Puzzle of Social Activity - The
Significance of Tools in Cognition and Cooperation,
2006, ISBN 91-85523-71-2.
Andrzej Bednarski: Integrated Optimal Code Generation for Digital Signal Processors, 2006, ISBN 9185523-69-0.
Peter Aronsson: Automatic Parallelization of Equation-Based Simulation Programs, 2006, ISBN 9185523-68-2.
Robert Nilsson: A Mutation-based Framework for
Automated Testing of Timeliness, 2006, ISBN 9185523-35-6.
Jon Edvardsson: Techniques for Automatic
Generation of Tests from Programs and
Specifications, 2006, ISBN 91-85523-31-3.
No 1035
No 1045
No 1051
No 1054
No 1061
No 1073
No 1075
No 1079
No 1083
No 1086
No 1089
No 1091
No 1106
No 1110
No 1112
No 1113
No 1120
No 1127
No 1139
No 1143
No 1150
No 1155
No 1156
No 1183
Vaida Jakoniene: Integration of Biological Data,
2006, ISBN 91-85523-28-3.
Genevieve
Gorrell:
Generalized
Hebbian
Algorithms for Dimensionality Reduction in Natural
Language Processing, 2006, ISBN 91-85643-88-2.
Yu-Hsing Huang: Having a New Pair of Glasses Applying Systemic Accident Models on Road Safety,
2006, ISBN 91-85643-64-5.
Åsa Hedenskog: Perceive those things which cannot
be seen - A Cognitive Systems Engineering
perspective on requirements management, 2006,
ISBN 91-85643-57-2.
Cécile Åberg: An Evaluation Platform for Semantic
Web Technology, 2007, ISBN 91-85643-31-9.
Mats Grindal: Handling Combinatorial Explosion in
Software Testing, 2007, ISBN 978-91-85715-74-9.
Almut Herzog: Usable Security Policies for Runtime
Environments, 2007, ISBN 978-91-85715-65-7.
Magnus Wahlström: Algorithms, measures, and
upper bounds for Satisfiability and related problems,
2007, ISBN 978-91-85715-55-8.
Jesper Andersson: Dynamic Software Architectures,
2007, ISBN 978-91-85715-46-6.
Ulf
Johansson:
Obtaining
Accurate
and
Comprehensible Data Mining Models - An
Evolutionary Approach, 2007, ISBN 978-91-85715-343.
Traian Pop: Analysis and Optimisation of
Distributed Embedded Systems with Heterogeneous
Scheduling Policies, 2007, ISBN 978-91-85715-27-5.
Gustav Nordh: Complexity Dichotomies for CSPrelated Problems, 2007, ISBN 978-91-85715-20-6.
Per Ola Kristensson: Discrete and Continuous Shape
Writing for Text Entry and Control, 2007, ISBN 97891-85831-77-7.
He Tan: Aligning Biomedical Ontologies, 2007, ISBN
978-91-85831-56-2.
Jessica Lindblom: Minding the body - Interacting socially through embodied action, 2007, ISBN 978-9185831-48-7.
Pontus Wärnestål: Dialogue Behavior Management
in Conversational Recommender Systems, 2007,
ISBN 978-91-85831-47-0.
Thomas Gustafsson: Management of Real-Time
Data Consistency and Transient Overloads in
Embedded Systems, 2007, ISBN 978-91-85831-33-3.
Alexandru Andrei: Energy Efficient and Predictable
Design of Real-time Embedded Systems, 2007, ISBN
978-91-85831-06-7.
Per Wikberg: Eliciting Knowledge from Experts in
Modeling of Complex Systems: Managing Variation
and Interactions, 2007, ISBN 978-91-85895-66-3.
Mehdi Amirijoo: QoS Control of Real-Time Data
Services under Uncertain Workload, 2007, ISBN 97891-85895-49-6.
Sanny Syberfeldt: Optimistic Replication with Forward Conflict Resolution in Distributed Real-Time
Databases, 2007, ISBN 978-91-85895-27-4.
Beatrice Alenljung: Envisioning a Future Decision
Support System for Requirements Engineering - A
Holistic and Human-centred Perspective, 2008, ISBN
978-91-85895-11-3.
Artur Wilk: Types for XML with Application to
Xcerpt, 2008, ISBN 978-91-85895-08-3.
Adrian Pop: Integrated Model-Driven Development
Environments for Equation-Based Object-Oriented
Languages, 2008, ISBN 978-91-7393-895-2.
No 1185
No 1187
No 1204
No 1222
No 1238
No 1240
No 1241
No 1244
No 1249
No 1260
No 1262
No 1266
No 1268
No 1274
No 1281
No 1290
No 1294
No 1306
No 1313
No 1321
No 1333
Jörgen
Skågeby:
Gifting
Technologies
Ethnographic Studies of End-users and Social Media
Sharing, 2008, ISBN 978-91-7393-892-1.
Imad-Eldin Ali Abugessaisa: Analytical tools and
information-sharing methods supporting road safety
organizations, 2008, ISBN 978-91-7393-887-7.
H. Joe Steinhauer: A Representation Scheme for Description
and
Reconstruction
of
Object
Configurations Based on Qualitative Relations, 2008,
ISBN 978-91-7393-823-5.
Anders Larsson: Test Optimization for Core-based
System-on-Chip, 2008, ISBN 978-91-7393-768-9.
Andreas Borg: Processes and Models for Capacity
Requirements in Telecommunication Systems, 2009,
ISBN 978-91-7393-700-9.
Fredrik Heintz: DyKnow: A Stream-Based Knowledge Processing Middleware Framework, 2009,
ISBN 978-91-7393-696-5.
Birgitta Lindström: Testability of Dynamic RealTime Systems, 2009, ISBN 978-91-7393-695-8.
Eva Blomqvist: Semi-automatic Ontology Construction based on Patterns, 2009, ISBN 978-91-7393-683-5.
Rogier Woltjer: Functional Modeling of Constraint
Management in Aviation Safety and Command and
Control, 2009, ISBN 978-91-7393-659-0.
Gianpaolo Conte: Vision-Based Localization and
Guidance for Unmanned Aerial Vehicles, 2009, ISBN
978-91-7393-603-3.
AnnMarie Ericsson: Enabling Tool Support for Formal Analysis of ECA Rules, 2009, ISBN 978-91-7393598-2.
Jiri Trnka: Exploring Tactical Command and
Control: A Role-Playing Simulation Approach, 2009,
ISBN 978-91-7393-571-5.
Bahlol Rahimi: Supporting Collaborative Work
through ICT - How End-users Think of and Adopt
Integrated Health Information Systems, 2009, ISBN
978-91-7393-550-0.
Fredrik Kuivinen: Algorithms and Hardness Results
for Some Valued CSPs, 2009, ISBN 978-91-7393-525-8.
Gunnar Mathiason: Virtual Full Replication for
Scalable Distributed Real-Time Databases, 2009,
ISBN 978-91-7393-503-6.
Viacheslav Izosimov: Scheduling and Optimization
of Fault-Tolerant Distributed Embedded Systems,
2009, ISBN 978-91-7393-482-4.
Johan Thapper: Aspects of a Constraint
Optimisation Problem, 2010, ISBN 978-91-7393-464-0.
Susanna Nilsson: Augmentation in the Wild: User
Centered
Development
and
Evaluation
of
Augmented Reality Applications, 2010, ISBN 978-917393-416-9.
Christer Thörn: On the Quality of Feature Models,
2010, ISBN 978-91-7393-394-0.
Zhiyuan He: Temperature Aware and DefectProbability Driven Test Scheduling for System-onChip, 2010, ISBN 978-91-7393-378-0.
David Broman: Meta-Languages and Semantics for
Equation-Based Modeling and Simulation, 2010,
ISBN 978-91-7393-335-3.
Linköping Studies in Arts and Sciences
No 504
Ing-Marie
Jonsson:
Social
and
Emotional
Characteristics
of
Speech-based
In-Vehicle
Information Systems: Impact on Attitude and
Driving Behaviour, 2009, ISBN 978-91-7393-478-7.
Linköping Studies in Statistics
No 9
Davood Shahsavani: Computer Experiments Designed to Explore and Approximate Complex Deterministic Models, 2008, ISBN 978-91-7393-976-8.
No 10
Karl Wahlin: Roadmap for Trend Detection and Assessment of Data Quality, 2008, ISBN 978-91-7393792-4.
No 11
Oleg Sysoev: Monotonic regression for large
multivariate datasets, 2010, ISBN 978-91-7393-412-1.
Linköping Studies in Information Science
No 1
Karin Axelsson: Metodisk systemstrukturering- att
skapa samstämmighet mellan informationssystemarkitektur och verksamhet, 1998. ISBN-9172-19-296-8.
No 2
Stefan Cronholm: Metodverktyg och användbarhet en
studie
av
datorstödd
metodbaserad
systemutveckling, 1998, ISBN-9172-19-299-2.
No 3
Anders Avdic: Användare och utvecklare - om
anveckling med kalkylprogram, 1999. ISBN-91-7219606-8.
No 4
Owen Eriksson: Kommunikationskvalitet hos informationssystem och affärsprocesser, 2000, ISBN 917219-811-7.
No 5
Mikael Lind: Från system till process - kriterier för
processbestämning vid verksamhetsanalys, 2001,
ISBN 91-7373-067-X.
No 6
Ulf Melin: Koordination och informationssystem i
företag och nätverk, 2002, ISBN 91-7373-278-8.
No 7
Pär J. Ågerfalk: Information Systems Actability - Understanding Information Technology as a Tool for
Business Action and Communication, 2003, ISBN 917373-628-7.
No 8
Ulf
Seigerroth:
Att
förstå
och
förändra
systemutvecklingsverksamheter - en taxonomi för
metautveckling, 2003, ISBN91-7373-736-4.
No 9
Karin Hedström: Spår av datoriseringens värden –
Effekter av IT i äldreomsorg, 2004, ISBN 91-7373-9634.
No 10
Ewa Braf: Knowledge Demanded for Action Studies on Knowledge Mediation in Organisations,
2004, ISBN 91-85295-47-7.
No 11
Fredrik Karlsson: Method Configuration method
and computerized tool support, 2005, ISBN 91-8529748-8.
No 12
Malin Nordström: Styrbar systemförvaltning - Att
organisera systemförvaltningsverksamhet med hjälp
av effektiva förvaltningsobjekt, 2005, ISBN 91-8529760-7.
No 13
Stefan Holgersson: Yrke: POLIS - Yrkeskunskap,
motivation, IT-system och andra förutsättningar för
polisarbete, 2005, ISBN 91-85299-43-X.
No 14
Benneth
Christiansson,
Marie-Therese
Christiansson: Mötet mellan process och komponent
- mot ett ramverk för en verksamhetsnära
kravspecifikation
vid
anskaffning
av
komponentbaserade informationssystem, 2006, ISBN
91-85643-22-X.
Was this manual useful for you? yes no
Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Related manuals

Download PDF

advertisement