RSL-Based Railway Control System Model
RSL-Based Railway Control System Model
Control System
Abstract
This thesis concerns the development of a distributed control system for a
simple railway line. Control systems exist to ensure safety of trains by prevent-
ing events like derailments and collisions.
Formal development methods and specification languages can increase the cor-
rectness of software systems. These methods are essential to the development
of safety critical systems where human lives are at stake. Therefore a formal
method is applied to the development in this thesis.
A formal model, using the RAISE specification language (RSL), of a distributed
control system for railway lines is developed. The formal specification language
is used to ensure correctness and safety of the system. The model is separated
in modules so a clear separation of the static, dynamics, and control properties
is obtained.
The model is constructed with provability of safety in mind. Proof obligations
are sketched and the theory of how to prove safety properties in the model is
briefly described. A single informal proof of one proof obligation is performed.
The model is refined through a number of steps. This is done by first specifying
an abstract applicative model which then is refined to a concrete version. The
concrete model is transformed to an imperative version.
The imperative model is implemented in the JAVA programming language. The
result is a generic simulator which can take a configuration (a railway line struc-
ture) as input and simulate trains operating on this line. A configuration editor
is developed to ease the construction of new railway configurations.
The developed model is fairly complex compared to other formally developed
models since it also concerns time issues. These complicate the model by adding
a considerably larger state space to the model. Events like collisions and braking
distances become major issues in the development.
Keywords: formal specification, railway lines, control systems, JAVA, XML,
simulation, safety, RAISE.
4
Resumé
Denne rapport omhandler udviklingen af et distribueret styresystem til en
simpel jernbane. Styresystemers opgave er at sørge for togenes sikkerhed ved at
forhindre visse situationer såsom afsporing og kollisioner.
Formelle metoder til udvikling og specifikation kan forøge korrektheden af soft-
ware systemer. Disse metoder er essentielle i udviklingen af systemer, hvor
sikkerheden er i højsædet, fordi menneskeliv er involveret. Derfor er formelle
metoder brugt i dette projekt.
En formel model af et sådant styresystem er udviklet ved at bruge RSL (RAISE
specification language). Det formelle specifikationssprog er brugt til at sikre at
systemet er sikkert og korrekt implementeret. Modellen er opdelt i moduler, der
adskiller de statiske, dynamiske og sikkerhedsmæssige egenskaber af systemet.
Modellen er konstrueret på en måde, så det er muligt at bevise sikkerheden
af systemet. Bevisforpligtelser er skitseret, og teorien for, hvordan sikkerheden
bevises, er beskrevet kort. En enkel bevisforpligtelse er bevist uformelt.
Modellen er trinvist forfinet. Først er en abstrakt applikativ model specificeret.
Dernæst er modellen gjort konkret, og tilsidst er den tranformeret til en imper-
ativ model.
Den imperative model er implementeret i programmeringssproget JAVA. Re-
sultatet er en generisk simulator, der tager en konfiguration (strukturen af en
jernbane) som input og simulerer togene på jernbanen. Desuden er der udviklet
et værktøj til at lave nye konfigurationer.
Den udviklede model er ret kompleks i forhold til andre formelle modeller, da
den også behandler tidsaspektet. Dette kompliserer modellen, da tilstandsrum-
met bliver forholdsvis stort. Situationer såsom kollisioner og bremselængder er
væsentlige emner i den udviklede model.
Nøgleord: formel specifikation, jernbaner, styresystemer, JAVA, XML, simu-
lation, sikkerhed, RAISE.
5
Preface
This paper is written to document the master thesis project Modelling a
Distributed Railway Control System - Formal Methods for Software Develop-
ment. The master thesis starts the third of January 2005 and is handed in the
first of August 2005. The project is performed at the department Computer
Science and Engineering (CSE) at the institute Informatics and Mathematical
Modelling (IMM) at Technical University of Denmark (DTU) in Lyngby.
The project is supervised by Associate Professor, Ph.D. Anne E. Haxthausen.
6
Contents
1 Introduction 21
1.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.2 Project motivation . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3 Formal methods and safety . . . . . . . . . . . . . . . . . . . . . 22
1.3.1 In general . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.3.2 RSL and levels of formality . . . . . . . . . . . . . . . . . 23
1.4 Thesis objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.4.1 Thesis concept diagram . . . . . . . . . . . . . . . . . . . 25
1.5 The railway domain . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.5.1 Railways in general . . . . . . . . . . . . . . . . . . . . . . 26
1.5.2 Control / safety Systems . . . . . . . . . . . . . . . . . . . 26
1.5.3 Railway accidents . . . . . . . . . . . . . . . . . . . . . . 27
1.5.4 Railways today . . . . . . . . . . . . . . . . . . . . . . . . 27
2 Thesis overview 29
3.4 Train . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.4.1 Static properties . . . . . . . . . . . . . . . . . . . . . . . 35
3.4.2 Dynamic properties . . . . . . . . . . . . . . . . . . . . . 36
3.5 Junction / point . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.5.1 Static properties . . . . . . . . . . . . . . . . . . . . . . . 36
3.5.2 Dynamic properties . . . . . . . . . . . . . . . . . . . . . 37
3.6 Crossing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.6.1 Dynamic properties . . . . . . . . . . . . . . . . . . . . . 37
3.7 Switch Box . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.7.1 Static properties . . . . . . . . . . . . . . . . . . . . . . . 38
3.8 Sensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.8.1 Dynamic properties . . . . . . . . . . . . . . . . . . . . . 39
3.9 Stations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.10 Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.11 An example of a railway line . . . . . . . . . . . . . . . . . . . . 40
3.12 Single lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
5 Engineering concepts 47
5.1 Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2 Reservation and brake points . . . . . . . . . . . . . . . . . . . . 48
5.3 Time modelling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.4 Safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.5 Deadlock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.6 Livelock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7 Simulator requirements 57
7.1 Train simulator requirements . . . . . . . . . . . . . . . . . . . . 57
7.1.1 Formal model requirements . . . . . . . . . . . . . . . . . 57
7.1.2 Visual parts . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7.2 Switch off the control system . . . . . . . . . . . . . . . . . . . . 58
7.3 Railway line configurations . . . . . . . . . . . . . . . . . . . . . 58
7.3.1 Create configurations . . . . . . . . . . . . . . . . . . . . 58
7.3.2 Export/import configurations . . . . . . . . . . . . . . . . 59
7.3.3 Load configuration . . . . . . . . . . . . . . . . . . . . . . 59
8 Model structure 61
9 Physical design 63
9.1 Static network modelling . . . . . . . . . . . . . . . . . . . . . . . 64
9.2 Train positions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.3 ESAs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
9.4 Crossings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
9.5 Points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
12 Glossary 89
13 GUI design 93
13.1 Train simulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
13.2 Configuration editor . . . . . . . . . . . . . . . . . . . . . . . . . 94
22 Test 207
22.1 Test configuration . . . . . . . . . . . . . . . . . . . . . . . . . . 207
22.2 Test strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
22.2.1 Basic tests . . . . . . . . . . . . . . . . . . . . . . . . . . 207
22.2.2 Performance tests . . . . . . . . . . . . . . . . . . . . . . 208
22.3 Test listings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
22.3.1 Basic test listings . . . . . . . . . . . . . . . . . . . . . . . 208
22.3.2 Performance test listings . . . . . . . . . . . . . . . . . . . 211
16 CONTENTS
23 Verification 213
23.1 The idea of provability . . . . . . . . . . . . . . . . . . . . . . . . 213
23.1.1 The safe predicate . . . . . . . . . . . . . . . . . . . . . . 213
23.1.2 The consistent predicate . . . . . . . . . . . . . . . . . . . 214
23.1.3 Preconditions (guards) . . . . . . . . . . . . . . . . . . . . 215
23.1.4 Wellformedness . . . . . . . . . . . . . . . . . . . . . . . . 216
23.1.5 The init req predicate . . . . . . . . . . . . . . . . . . . . 217
23.1.6 Verifying control algorithm . . . . . . . . . . . . . . . . . 217
23.2 Proof obligations . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
23.2.1 [gen wf pres] . . . . . . . . . . . . . . . . . . . . . . . . . 218
23.2.2 [gen safe pres] . . . . . . . . . . . . . . . . . . . . . . . . 218
23.2.3 [gen consistent pres] . . . . . . . . . . . . . . . . . . . . . 218
23.2.4 [init is safe] . . . . . . . . . . . . . . . . . . . . . . . . . . 218
23.2.5 [init is consistent] . . . . . . . . . . . . . . . . . . . . . . 218
23.3 Proof: [init is safe] . . . . . . . . . . . . . . . . . . . . . . . . . . 219
26 Discussion 229
26.1 Predicates and preconditions . . . . . . . . . . . . . . . . . . . . 229
26.1.1 Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
26.1.2 Preconditions . . . . . . . . . . . . . . . . . . . . . . . . . 229
26.2 A safe algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
26.2.1 Two trains collide . . . . . . . . . . . . . . . . . . . . . . 230
26.2.2 Collisions at a crossing . . . . . . . . . . . . . . . . . . . . 230
26.2.3 Derailing at a junction . . . . . . . . . . . . . . . . . . . . 231
26.2.4 External events . . . . . . . . . . . . . . . . . . . . . . . . 231
27 Conclusion 233
27.1 Summary of results . . . . . . . . . . . . . . . . . . . . . . . . . . 233
27.1.1 RSL model . . . . . . . . . . . . . . . . . . . . . . . . . . 233
27.1.2 Control system / algorithm . . . . . . . . . . . . . . . . . 233
27.1.3 XML configuration language DTD . . . . . . . . . . . . . 234
27.1.4 JAVA train simulator . . . . . . . . . . . . . . . . . . . . 234
27.1.5 JAVA configuration editor . . . . . . . . . . . . . . . . . . 234
27.2 Evaluation of results . . . . . . . . . . . . . . . . . . . . . . . . . 235
27.2.1 Design method . . . . . . . . . . . . . . . . . . . . . . . . 235
27.2.2 Train dynamics analysis . . . . . . . . . . . . . . . . . . . 235
27.2.3 Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
27.2.4 Verification . . . . . . . . . . . . . . . . . . . . . . . . . . 236
27.2.5 Modelling method . . . . . . . . . . . . . . . . . . . . . . 236
27.2.6 JAVA translation method . . . . . . . . . . . . . . . . . . 237
29 Bibliography 241
E Concurrency 261
E.1 Concurrency in RSL . . . . . . . . . . . . . . . . . . . . . . . . . 261
E.2 Concurrency in JAVA . . . . . . . . . . . . . . . . . . . . . . . . 261
E.3 Shared variables in RSL . . . . . . . . . . . . . . . . . . . . . . . 262
E.4 Shared variables in JAVA . . . . . . . . . . . . . . . . . . . . . . 263
E.5 Channel communication in JAVA . . . . . . . . . . . . . . . . . . 264
E.5.1 Socket communication . . . . . . . . . . . . . . . . . . . . 264
E.5.2 Shared varibles . . . . . . . . . . . . . . . . . . . . . . . . 264
E.5.3 Direct function call . . . . . . . . . . . . . . . . . . . . . . 265
Introduction
This report is written as documentation for the master thesis project mentioned
in Preface at page 5. The main goal of this project is to develop a model of
a distributed control system for a railway line. The model is specified using
the formal specification language RSL (RAISE1 Specification Language). The
model is later implemented as a graphical simulator written in the JAVA pro-
gramming language.
It is a primary concern of this project to use formal specification and refinement
in the development process.
1.1 Background
At CSE, DTU much work has been done in the field of modelling railways
and different control systems. The creation of methods to ease and generalize
this work has also been a goal. Associate Professor Anne E. Haxthausen has
played a major role in this in cooperation with Professor Jan Peleska from the
University of Bremen. Together they have published several papers on this
topic. A number of students have done special projects or master thesis’ in the
field of modelling railways or control systems which were supervised by Anne.
This project follows in the foot steps of this work and in particular of [1].
In [6] a simple simulator for a basic interlocking system was modelled and im-
plemented as a discrete event based simulator.
Both projects did not concern the issue of time and only targeted the actual
changes in the state of the control system. The issue of time was not modelled in
these projects because safety should be provable and time would only complicate
matters further.
When a model puts aside the concept of time, issues, such as braking distances
and collision detection, do not arise.
The idea of this project is to construct a system which deals with all of the
issues mentioned above thus combine modelling physical and control aspects of
the system. This also means that proving the system to be absolutely safe is
out of the scope of this project, but the ideas of proof techniques (chapter 23)
and some informal argumentation is done (section 26.2).
The model in this project has a fully independent physical module which models
the behavior of actual trains driving on a track. Therefore a lot of other aspects
comes into scope of this project. Instead of just considering IF a train may
enter a track segment we also have to consider if the train can be able to brake
BEFORE entering the segment.
These physical aspects make the elicitation of requirements to the system much
more realistic.
1.3.1 In general
ensure confidence in the software system. But what is the use of spending
many resources on verifying the software if the underlying hardware is subject
to failure and instability?
These are questions which must be considered before any development is initi-
ated.
As described in [3] the RAISE method and RSL can be used in many and flexible
ways. In section 1.3.1 it is mentioned that different levels of formality can be
applied to the development of a software system. Therefore development using
RSL and the RAISE method is not bound to any static procedure or required
actions.
In the most simple case RSL can be used as a very abstract requirement spec-
ification which then serves as a programming guideline and a contract for the
developers of the system.
To take the formal development one step further, the abstract specification
could be refined into a concrete specification and an implementation relation
could be specified. An implementation relation specifies that a specification is
an implementation of another specification.
A specification is only an implementation if all axioms from the other specifica-
tion is true in this new specification. This relation could be reviewed without
any actual formal justification or verification.
To further increase the level of formality the implementation relation between
the different specifications could be justified starting with the most important
ones leaving out all the trivial and well known modules.
As a last resort all modules could be justified to increase trust in the software
reliability.
One critical step in the development though is the translation step. A translation
involves translating the formal specification to a specific programming language.
This translation process does not include any formalization and guarantee of
correctness, unless the code is automatically generated from the specification
using a previously proved translator.
It is essential for the RSL development, that strict procedures are enforced when
translating the RSL into a specific programming language. Else all proofs and
formality would seem pointless.
24 Introduction
The thesis objectives described above are marked with gray background. These
are:
1. RSL model.
4. Java Simulator.
26 Introduction
Railways (and trains) have since their invention been used for both transporting
cargo / goods and passengers. Long railway lines (tracks) have been constructed
throughout Europe for these purposes.
In Denmark exists fairly complex railway networks with lines coming from many
destinations merging into one track using junctions and points that can switch
between the incoming tracks. One example of this could be the S-train (Danish:
S-tog) that covers most of the capital region of Zealand (Danish: Sjælland).
In this thesis we focus on small simple railway lines between two destinations.
The railway line may be branching into two tracks but this is only for trains to
pass each other in opposite directions (at intermediate stations). These small
lines are characterized by having low intensity traffic and that the trains do not
overtake each other.
A good example is the train running from Hillerød to Tisvildeleje. Another is
the Nærum line in Lyngby. These are both private lines with low density traffic.
Safety system Does not directly control an entity but feeds the controller of
an entity with information that helps to safely control the entity.
Control system Is a system which actively controls an entity and its actions
/ movement. This system also implements a safety system upon which
the control system gets its data. Without safety such an automatic con-
trol system would be useless because it would require constant human
observation.
Interlocking systems
The interlocking system is a very basic safety system which purpose is to prevent
trains from colliding and derailing. A basic interlocking system operates on the
1.5 The railway domain 27
One of the most popular control systems for trains is the ATC system. This
system automatically monitors and manages maximum velocity, stop at red
signals and other safety related activities. Without getting into details the
ATC system kicks in if the train driver violates the safety procedures of the
railway.
Many variations of this system has been implemented utilizing only subsets of
the ATC system due to the massive cost of implementing full ATC. [4] [11].
Though train accidents are fairly rare when compared to car accidents a great
deal of effort is put into development of train safety and control systems. One
can argument that the cost of development is too high compared to the minimal
effect in form of saved lives.
Research has shown that people are willing to accept greater risk when in con-
trol themselves (as in a car). Much higher demands are put on trains where
people feel that they put their lives in the hands of another person or authority.
Therefore to ensure popularity among passengers trains has to offer a high level
of safety even if it really is unnecessary in some way.
On the other hand, when a train accident do occur, the loss of life and equipment
damage is much higher than in a normal car accident. The cost to the society
in the form of delayed traffic and repairs is also much greater and is therefore
center of attention to the media which again makes the public very much aware
of every single accident that occur. [11]
Railways in Europe today have a large variety of control and safety systems.
Until a few years ago there had not been introduced any form of standardization
of automatic train control in the European countries. Due to this lack of stan-
dard nearly all countries have invented their own form of train control systems.
28 Introduction
Safety in Denmark
system
Chapter 2
Thesis overview
This chapter presents an overview of all chapters in this thesis. The chapters in
this document are organized as the phases in this project. This means that the
chapters in this report are ordered chronologically as the phases where executed.
Chapter 4: Main idea and concept This chapter explains the main ideas
of how to solve the problems which can arise on a simple railway line.
The main concept of a control system and how this will work is sketched.
Chapter 6: Control system requirements This chapter lays out the re-
quirements to the control system. Solutions to these requirements are
sketched. These are the ideas of the basic functionality of the control sys-
tem. These solutions are later transformed to a control algorithm. This
algorithm is described in chapter 11.
Chapter 9: Physical design This chapter describes the design decisions the
physical domain in lack of control (the domain described in chapter 3).
All design decisions and considerations are listed here, but no data type
or model specific information is listed.
Chapter 10: Train dynamics analysis In this chapter the dynamics of trains
and the derived physical requirements to the system are elicitated and
calculated. Many requirements are necessary for the system to stay con-
sistent. This chapter reflects the many physical aspects that the project
has adopted compare to using a highly discrete physical model.
Chapter 11: Control system design This chapter describes the design of
the control system. All the algorithms of the control entities are shown
as state flow diagrams, and the overall control algorithm and a sample
scenario is presented.
Chapter 12: Glossary This is a glossary of all domain specific terms used in
this report.
Chapter 13: GUI design This chapter lays out the design of the GUI to the
model implemented in JAVA. Some prototype screens are shown.
Chapter 14: Invariants and assumptions This chapter lists all the invari-
ants and assumptions that have been identified and found necessary in the
design and analysis chapters. All these invariants should be implemented
in the model in such a way that they are enforced in the implementation.
Chapter 15: RSL modelling method summary This chapter summarizes
the method used to construct the RSL model, how it is refined and decom-
posed, how the requirements and safety is enforced, and how the structure
is prepared for proving safety in the model.
Chapter 16: Initial model An illustration of the initial model schemes is
shown. A short description of the initial model which is abstract is pre-
sented. All major data types are therefore also abstract (sorts).
Chapter 17: Decomposed model A short description of the decomposed
model where related data has been grouped into modules (objects).
Chapter 18: Concrete model A short description of the concrete model where
all major data types has been explicitly defined.
Chapter 19: Imperative model A short description of the imperative model.
Variables have been added to the model and all functions are converted
from applicative to imperative to prepare the model for translation into
JAVA.
Chapter 20: Implementing a simulator The method of translation from
RSL to JAVA is discussed. The structure of the actual program which is
converted from RSL to JAVA is described.
31
Chapter 21: Using the simulator A small users guide to the simulator and
an introduction to simulator functionality.
Chapter 22: Test This chapter lays out the test strategy of the simulator and
presents some test results.
Chapter 23: Verifying safety This chapter presents a discussion of prov-
ability of safety in the system. Some methodology is presented of how to
do this, and some informal argumentation is done on some selected areas
following this method to prove safety.
Chapter 24: Ideas & future work Presents all ideas for further develop-
ment of the system. All ideas and considerations discussed when this
project was executed are included.
Chapter 25: Related work Related work in the form of papers and projects
are discussed and related to this project.
Chapter 26: Discussion Selected subjects are discussed
Chapter 27: Conclusion The results of this thesis are evaluated and com-
mented.
Appendix A: Design of the GUI Images of the GUI design prototypes
Appendix B: RSL method description Describes the method used and steps
taken developing the RSL model without being specific to the developed
model.
Appendix C: XML DTD The DTD describing the syntax of the XML con-
taining a configuration
Appendix D: Test images Images from the test
Appendix E: Concurrency Describes the ideas for using concurrency in the
RSL model and the translation to JAVA.
Appendix F: RSL modules All the modules of the model in the different
refinement steps
32 Thesis overview
Chapter 3
Informal domain
description
• Railway line
• Segments
• Trains
• Junctions / points
• Crossings
• Switch boxes
• Sensors
34 Informal domain description
3.2 Segment
The railway line is divided into a number of coherent segments. A segment is
basically just a division of the railway line. At each end of a segment is a switch
box (see section 3.7).
The segments are used by the control system which, through the switch boxes,
controls access to each segment (see section 11.1).
At the border between two segments (at a switch box, see section 3.7) there is
often an entity like a junction (see section 3.5) or a crossing (see section 3.6)
which needs special handling (controlled by a switch box). These entities are
modelled as point shaped, i.e. there is not free space between two segments.
Being located on a junction or on a crossing then means to be located on two
segments - one on each side of the entity.
After a while, located in an ESA, the train might change direction and drive to
the opposite end.
Access to the ESAs are controlled by the switch boxes (see section 3.7) at the
ends of the railway line.
An ESA is assumed to have an infinite capacity of parked trains. In the real
world it would of course have a finite capacity, but since the number of trains is
supposed to be very small in this railway line, the assumption should not cause
any problems.
The ESA in the low end is called the low ESA and the ESA in the high end is
called the high ESA.
• End : the end of the railway line at which the ESA is.
3.4 Train
A train is a number of connected vehicles that moves on a railway line. While
moving along the line the train enters and exits segments along the route. It
is assumed that the length of a train is always less than the length of any
segment. Therefore a train is either on one or two segments at a time. It is on
two segments when it passes from one segment to another.
Each train has a train driver that manually controls the train and a Train
Control Computer (TCC) that is used in the control system to reserve segments
before entering, and stop the train when it tries to enter a segment it has not
reserved. The TCC also gives relevant information to the train driver.
• Max deceleration (braking capacity): the max braking capacity of the train.
Figure 3.1: A railway line with four segments, two junctions and their points
3.6 Crossing
A crossing is a construction enabling a railway line and a road to cross each
other in the same level. Crossings are equipped with signals with both visual
and audio warnings and with barriers. These are used to preserve safety by
stopping cars etc. from entering a crossing when a train is about to cross.
Figure 3.2 and 3.3 shows crossings.
Figure 3.2: A crossing seen from the road with signals and barriers
• End SBs with one bordering segment at one of the ends of the railway
line and an ESA at the other end.
• Point SBs with three bordering segments at a junction/point (stem, up
branch and down branch).
• Crossing SBs with two bordering segments at a crossing - one segment at
each side of the crossing
• Plain SBs with two bordering segments - one at each side of the SB. It
is primarily used if it is preferred to split up a large segment in several
smaller segments.
End SB :
3.8 Sensor 39
Point SB :
Crossing SB / Plain SB :
Plain SB :
3.8 Sensor
A sensor is located at the boundary between two segments (at a SB). It senses
if a train is located on it, i.e. if a train passes from one segment to another.
The switch box at the sensor can read the state of the sensor.
• Active status: whether the sensor is active or not, i.e. whether a train is
located on it or not.
3.9 Stations
In the railway line we have already introduced the main stations, which are the
two ESAs. Besides these, minor stations can freely be placed along any segment.
Typically they are placed between two branch segments (figure 3.4) but it does
not have to be the case.
The minor stations are not included in the formal model, since they have no
impact on the control system. Trains are not statically located (parked) at minor
40 Informal domain description
3.10 Signals
Some railway networks use signals as a part of the control system to show the
train driver if the train is allowed to proceed. This is not the case in the system
considered here. The control system is formed by the switch boxes and the
on board train control computers, that control the trains and give go/no-go
information to the driver. Therefore signals are not necessary.
This chapter presents the problems which are solved by this thesis. The main
idea and concept behind the solution to these problems is presented. Some
terms concerning the domain are also explained.
The line is simple in the way that it only runs from one end to another. When the
line branches, it immediately joins again. Trains driving in opposite directions
can pass each other at these branches.
Three basic problems arise on this simple line:
Deadlocks occur when two trains are on the same line and face each other.
Then one train has to reverse to a branch and let the other train pass.
The control system adjusts parameters in the physical system to uphold safety.
The control system obtains knowledge of state information by using equipment
as track sensors, GPS and other well-known technologies.
For the control system to be able to control train access to different parts of the
line, the line is separated into several segments. The idea of the control system
is to allow only one train at a time at a given segment.
At each end of a segment a switch box is placed to guard the entrance (like a
signal). A train on-board control computer (TCC) communicates with a switch
4.2 Control system 45
As mentioned in section 4.2.1 a train has to reserve the next segment through a
switch box to gain access to the segment. Figure 4.4 illustrates two fixed points
on a segment:
This illustration shows the reservation point (res) and the brake point (brk ).
These dictate respectively that when a point on the segment is passed then the
train has to:
• Ask for a reservation for next segment (when passed reservation point).
• Brake the train if no reservation has been obtained (when passed brake
point).
For calculations concerning acceleration and braking we assume that trains have
a constant acceleration / braking coefficient. This is not the case in the real
world though. In the real world the braking coefficient is based on friction which
is heavily dependent of the speed of the train.
Chapter 5
Engineering concepts
This chapter explains some technologies, assumptions about these, and terms,
which are basic to this thesis.
5.1 Sensors
In the model developed in this thesis a sensor is located at a switch box, which
is situated at the border between two segments.
When a train passes from one segment to the next, the sensor becomes active at
the time the front end of the train enters the new segment. The sensor becomes
inactive again when the rear end of the train enters the new segment. This is
an abstraction from the real world in which several types of sensory technology
is used:
If the actual track is equipped with isolations we assume that the SB has some
kind of interface to this sensory input. The SB has to use this input to determine
if a train is passing by and thereby mapping the input to correspond to a single
point sensor placed at the SB. We can consider the following possibilities:
Because of the system design structure the SB knows that a train passes
if both isolations are active at the same time. This is true because the SB
has to give permission before a train can pass it.
So if both isolations are active at the same time without a permission is
given, two different trains occupy the two segments at each side. This also
means that if an error occurs in the system, the SB (in this case) cannot
be certain how to interpret the sensory input.
• A point SB is placed at a junction between 3 segments. If each segment
has its own isolation - like in the example above - the result is exactly the
same. If the SB cannot trust its local reservation information it has no
way of knowing if two active isolations is one train passing or two different
trains occupying one segment each.
But if the junction itself has an isolation (like in figure 5.1) the function-
ality can be mapped directly to the behavior of a sensor. The SB knows
if a train is positioned on the junction or not.
Axle counters some units that counts the axles on a train are placed on the
track. When a train passes over this unit it counts how many axles that
passes. The system knows that a train exists between two axle counter
units until an equal number of axles have passed them both.
Apart from the difference in technology the sensory information is the
same. The system knows if a train exists on a specific length of track.
Also, for the system to work, a train must not acquire a new reservation while
on the border between two segments. Therefore the following requirement:
Parallel updates all entity time updates are handled concurrently. This gives
rise to the need of synchronizing all variables which are shared between
the entities of the system.
50 Engineering concepts
Sequential updates all entities are called one after another. The processing
of time update in one entity is terminated before another is executed.
Beside the major difference in the structure of the two implementations there
is essentially no effectual difference in functionality. Because of the discretized
time updates all time processing in all entities should have terminated before
the next tick. If this is not ensured then some entities could be further ahead
in time than others.
This effectually eliminates the advantages of concurrency since some kinds of
barrier synchronization is needed after each tick anyway.
The messages between switch boxes and trains are modelled to arrive instantly.
Some communication delay could be modelled but the system should be designed
so the system is not dependent on fast message delivery. Each control entity
have a message buffer that receives messages independently of a tick. At each
tick the control entity processes a message from the buffer.
5.4 Safety
The railway line is required to be safe in all possible situations when using the
system. The railway line is considered safe (for trains) when certain events are
avoided. This definition of safety does not concern exceeding max speed.
The railway line is safe when:
• Any physical defects in the railway system that causes the system to fail
like cracks in the railway line and broken electrical wires.
5.5 Deadlock 51
The last two situations are caused by external circumstances and are not consid-
ered in the model. Although they should at least be considered for the individual
implementations of the system. An example could be the danish S-train system
which quite often (several times a month) experiences electrical failures in both
trains and railway power supply wires.
5.5 Deadlock
• Two or more trains are waiting for each other to move before they are
able to move themselves. In this situation they will never be able to do so
without either violating the rules of the control system because they are
all just passively waiting for each other to move. Without some deadlock
resolving algorithm the system will never leave this state.
In both examples the safety requirements (as described in section 6.1) prohibit
the trains from entering the same segment. The trains will therefore not collide,
but to make progress one of the trains has to change direction. This is not
desired since all trains are supposed to drive continuously between the two ends
of the railway line without changing direction half way (if ever this is possible).
52 Engineering concepts
5.6 Livelock
Livelock of trains can be very hard to avoid. A situation with livelock is defined
as:
• One or more trains are currently not able to move to another segment but
eventually it may be able to do so without either violating the rules of the
control system or performing an undesired action.
Livelock is in many ways like deadlock. The difference is that at deadlock you
are stuck with no future possibility to proceed. At livelocks you often have this
possibility.
Figure 5.5 shows an example of livelock.
In figure 5.5 livelock can arise if both trains continually ask for a reservation for
the same branch at the same time.
Chapter 6
Control system
requirements
This chapter concerns the requirements to the distributed control system. These
are the safety requirements and some functional requirements.
The requirements are listed together with sketched solutions to the require-
ments. These solutions will be part of the control system design. To see how
this is reflected in the design please refer to chapter 11.
A glossary is provided in chapter 12 to explain the terms used in the require-
ments.
• Two trains are not allowed to be positioned on the same segment at the
same time.
Solutions:
• At any time deadlock must be avoided. To make sure that deadlock does
not occur, any situation that can lead to deadlock must be avoided. (Two
examples of deadlock are illustrated in section 5.5).
• Livelocks where train requests could conflict with each other should be
avoided. (An example of a possible livelock is illustrated in section 5.6).
Solution:
• A train must always use the right branch of a junction (seen from its
driving direction). This makes the branches at a junction unidirectional
so that trains always pass each other to the right. Since the trains are not
supposed to overtake each other this does not constitute a problem in the
workings of the railway line.
This solution avoids the second deadlock example and the livelock exam-
ple.
6.2 Functional requirements 55
Using the convention of always using the right branch, the right branch
seen from the up direction is called the up branch. Likewise the right
branch seen from the down direction is called the down branch. Using the
terms up- and down branch we have uniquely named the branches of a
junction/point. These terms are therefore used in the following sections.
• Before a train enters a line where traffic in opposite direction is possible,
the whole bi-directional line must be reserved until a segment which is
only uni-directional.
This should prevent the first example of deadlock in section 5.5.
To see how these solutions are implemented in the control algorithm please refer
to chapter 11, Control system design.
56 Control system requirements
Chapter 7
Simulator requirements
The basis for the train simulator is the concrete imperative model of the phys-
ical railway line and its control system. The model should systematically be
transformed into JAVA code as described in section 20.1. The JAVA code
transformed from the RSL model is called the simulator core.
The GUI should also make it possible to change the state of the different dy-
namic entities in the railway line. The accelerate, brake and change direction
commands are available to act as the train driver. These can be used in con-
junction with the control system which will handle undesired actions initiated
by the train driver
The actions to switch points and crossings are on the other hand not handled
by the system because this should not be a possibility in an actual system
implementation. These actions are only for experimental purposes:
Model structure
By concept is meant that this UML diagram only illustrates what information
should be reflected in the different model modules and not how they should be
structured.
For example one can see that both crossings and points are parts of the com-
posite entity SB. This is not necessarily how the module structure will be im-
plemented in the model, but we know that a SB should have the information of
a crossing and a point represented somewhere.
62 Model structure
Chapter 9
Physical design
This chapter concerns modelling the physical part of the railway system and
discusses how to model the physical domain in lack of any kind of control or
safety aspects.
This chapter do not mention any type- or function specific details about the
actual model design but only a high level strategy of what is to be modelled.
9.3 ESAs
9.4 Crossings
Figure 9.3 sketches a state chart for a crossing. Be aware that the state graph
is constructed to perform one transition per tick (see section 5.3). The vari-
ables signals only and bars moving represent the time needed to perform the
associated action.
9.5 Points
Figure 9.4 sketches the state chart of a point. The state graph is constructed to
perform one transition per tick (see section 5.3). The variable point switching
represents the time needed to switch a point.
At each tick with time interval t the train physics module should calculate the
following:
Velocity: v1 = v0 + a ∗ t
Acceleration: Set by control system and external events (train driver and
control system).
As the figure shows, the front of the two trains overlaps just a tiny bit. One
could argue that, seen strictly from a mathematical point of view, a collision is
when any part of two trains overlaps. This means that the situation showed in
figure 10.2 mathematically also is a collision.
We have decided only to handle the initial situation of a collision, i.e when the
first overlap of train positions is detected. That is when a train tries to move to
a location which is already occupied by another train. This means that we do
not intend to check collisions on the entire state at each update, but only check
on a train which is about to move.
To make this approach work, the time update interval has to be sufficiently
small to detect a collision before the trains have passed the initial part of the
collision, which is the only part that is detected. This is discussed further in
section 10.3.
This leads to the following two collision types:
In figure 10.1 we have a classic frontal collision. In this case a collision is defined
as:
In this figure a train has collided with the rear end of another train. This
collision type can be defined like this:
• One train has a front position which is higher UP than the other
trains rear position but lower than the other’s front position.
The opposite case, where both trains are driving DOWN, has the exact same
definition when switching UP / DOWN and higher / lower in the statements
above.
In this definition it is reflected that we only check on collisions from the point
of view of the train which finally moves into another train. Therefore the above
definition only concerns the train driving into the other’s rear and not the train
being hit.
Collision detection concerns the method used to detect if two trains have collided
in a given state. Collision detection can easily be very expensive in time critical
computations, because the calculations have to be done in every state of the
system. Of course the calculations in this case are only executed if two trains
are located on the same segment.
The actual collision detection is done by carrying out the algorithm sketched in
section 10.2. But for this to work we have to make sure that the time between
two updates is so small, that all collisions are detected. This is not possible if
the time update interval is set to a large value (e.g 10 seconds or so). Then
the collision detection (and all other processing in the system) is only executed
every 10th second. 10 seconds is more than enough for two trains to pass through
each other in opposite directions. Therefore it is not enough to ensure that all
collisions are detected.
A frontal collision is the fastest way for two trains to close in on each other.
Therefore it represents the worst case scenario of what the system needs to
detect. Furthermore we would like the collision to be detected before the trains
have driven too far through each other. It is therefore relevant to investigate
how far two trains could drive through each other using an example interval.
Two trains t1 and t2 are positioned toward each other and are both driving with
the highest possible speed vmax . The time is updated each ∆t seconds. The
distance serr that they both travel in ∆t seconds is then:
If we assume that the max speed of the train is 120 km/h ≈ 33 m/s, and we
assume that ∆t = 0.05s (system updated 20 times/s) then we get:
where tlengthmin is the length of the shortest train in the system. If this is
fulfilled then no front of another train can manage to go all the way through
the shortest train without being detected.
As seen in the last section, serr is the greatest distance a train can travel before
the system is updated and the control system checks and reacts upon the state
of the physical world. This leads to the following requirement of the system:
where bp is the length from the brake point to the end of the segment and sbrk
is the length used to brake if the train is running at maximum velocity vmax
and braking with the acceleration abrk .
sbrk is calculated by the following:
First we need to calculate the time used to brake tbrk :
1
sbrk = vmax ∗ tbrk + ∗ abrk ∗ t2brk ⇔
2
2 1 1 1 2
sbrk = −(vmax )∗ + ∗ ∗ vmax ⇔
abrk 2 abrk
1 v2
sbrk = − ∗ max (10.3)
2 abrk
Using the numbers from the example above and assume a braking capacity of
(−1.3m/s2 )1 we get:
bp sbrk + serr ⇔
>
1 v2
bp > − ∗ max + vmax ∗ ∆t ⇔
2 abrk
1 (33m/s)2
bp > − ∗ + 33m/s ∗ 0.05s ⇔
2 1.3m/s2
bp > 22.59m
To make sure that an ESA is long enough for a train to be able to brake entirely
the following requirement must hold:
The error of using discrete time updates are also reflected in the speed checking
system of the TCC.
Due to the delay of ∆t seconds in the simulation the train could theoretically
spend this time accelerating at max acceleration even though it has passed the
max velocity limit.
Using the current set of requirements, the speed checking system only checks if
[Link] > [Link]. In the following it is assumed that [Link] =
[Link]. ∆t seconds will pass before the control system again checks
the speed of the train. The speed has then exceeded the max speed by:
1 The average braking capacity of passenger trains found by searching the web. This could
verr = a ∗ ∆t
Therefore the control system must check if the following property is true:
Acceleration is the only property that the control system can change in the
physical train (by applying speeder / brakes). This means that the acceleration
is not time dependent and thereby not automatically calculated from the value
in last time update (like in the case with velocity).
A problem in using a discrete time model arises if the acceleration is not constant
in the time interval between the updates (this is possible if the control system
is updated concurrently and independently of the physical system). The error
caused by this can of course be minimized by choosing a low tick interval.
The error in position is calculated by the following scenario where a is set to
a new value during a tick t = t0 + t1 . The tick is separated in t0 (where the
acceleration is a0 ) and t1 (where acceleration is a1 ):
1
errpos = ∗ ∆a ∗ t0 + a1 ∗ t0 ∗ t1
2
t0 is the time from the beginning of the interval to the time where the accel-
eration is changed. So if the acceleration is changed during a tick, the entire
tick interval is handled as if it had the same acceleration as in the end of the
interval. t0 is thereby the time spent with the wrong acceleration value.
In any case this update interval must be very small compared to the speed of
the train. This is a consequence of the fact that the control system is based on
the input from the physical model. If this system is only updated, e.g. once
every minute, the control system will probably never notice that the train is
nearing the segment brake point. This corresponds to if a train driver was only
allowed to open his eyes once a minute.
Another approach to eliminate the calculation error is to update the control
system at each tick after the physical system is updated. This synchronizes the
physical system and control system updates.
The latter approach is chosen in this project. It does not make any sense that
the control system is checking several times on a state that does not change.
74 Train dynamics analysis
Chapter 11
This section describes how reservations are obtained in the control system.
In general, when a train (T1) (figure 11.1) needs to enter the segment in front of
it (S1), the TCC sends a segment request to the first SB in its driving direction
(SB1). The SB then finds out if it may give the train a segment reservation for
the segment and communicates the result back to the train.
The TCC only needs to know whether or not it has obtained a segment reser-
vation for the segment it is about to enter. It does not know any other details
about how reservations are managed by the SBs.
76 Control system design
Safety aspects in SB
The SBs have another notion of reservations, since they must make sure that
deadlock (see section 5.5) is avoided. This is done by having three different kinds
of reservations: line reservation, branch reservation and line-segment reserva-
tion. These are described in the glossary in chapter 12 and in the scenario
below.
A sample scenario
In the following a small scenario is explained where a train drives from one
branch on a railway line to another. The point is to show what happens in the
SBs along the route when the train progresses and continuously asks the SBs
for permission to enter the next segment.
Figure 11.2, 11.3, 11.4 and 11.5 show a part of a railway line. These figures are
used in this sample scenario.
First request Before the train can enter segment S1 it must obtain a segment
11.1 Control system algorithm 77
reservation for S1. Therefore the TCC requests the SB in front of it for
permission to enter the segment.
Check reservation SB1 checks its local state for any existing line reservation.
There may only be one line reservation at a time in a SB.
SB1 requests line and branch SB1 sends a message to SB3 to obtain a reser-
vation for the line between them and the branch S3a guarded by SB3.
SB3 replies Line reservations are saved in the two single line guards (SB1 and
SB3). The branch reservation of S3a is only saved in SB3. This is because
each branch is unidirectional and therefore only need a guard in one end.
Line-segment reservations are not saved in a SB since they only exist to
ensure that the line segment is prepared for a train to pass. Besides, only
one train is allowed to be at the single line at a time, so it is not necessary
to save the line-segment reservations in all intermediate SBs.
SB1 prepares first segment If S1 needs preparation (i.e. the point needs
to be switched to the appropriate branch) then this is handled before a
positive reservation message is returned to the train.
If the single line ends at an ESA there is no branch segment. Therefore only
the line reservation should be obtained in SB3.
Train enters S1 If the reservations are obtained, SB1 returns a segment reser-
vation for S1 to the TCC of the train. Then the train can proceed to S1.
Otherwise SB1 returns negative response to the TCC indicating that the
segment reservation could not be obtained.
Train progresses along the line Each time the train is about to enter a new
segment, it requests a reservation for that segment at the next SB. If
anything requires preparation (like closing a crossing) before the train can
pass, this is done before a positive response is sent from the SB to the
train.
78 Control system design
Train enters S3a When the train is located at the segment just before SB3
and wants to enter S3a, it request SB3 for a segment reservation for S3a.
This is given when S3a is prepared (as with line-segment reservations).
Note that the branch reservation is already obtained. Therefore the S3a
only needs to be prepared.
Line reservation cleared When the train enters S3a and thereby exits the
single line, SB3 sends a dereservation message to SB1 to clear the line
reservation.
Branch reservation cleared When the train exits the S3a branch segment
and passes the sensor of SB4, SB4 sends a dereservation message for the
branch to SB3.
The next section explains in detail the algorithms used in the TCC and the SB.
It is the job of the TCC to make sure that the train does not drive too fast.
The speed checking algorithm is shown in figure 11.7.
When the algorithm is executed, it first checks if the train is entirely in an ESA
or not. The reason for that is that the rules for determining whether a train
80 Control system design
drives too fast is different for ESAs and segments. In both cases a train is not
allowed to drive faster than the max allowed speed of the train. A train located
on a segment also drives to fast if it exceeds the max allowed speed for the
segment.
When a train leaves a segment and enters the next, it must have a segment
reservation for the next segment. This reservation is removed when the train
enters the segment.
Figure 11.8 shows how this is done. Whenever a train is located on two segments
(or a segment and an ESA), the segment reservation is removed if it exists, i.e.
if it has not already been removed.
It is the job of the TCC to make sure that the train has a segment reservation
for the segment it is about to enter. Therefore the TCC makes requests for
segment reservations and brakes the train if it is about to enter a segment it
does not have a segment reservation for.
The terms reservation point and brake point (see chapter 12) are used in the
following, see figure 11.9.
When a train (T1) passes the reservation point(R.P.) the TCC requests SB2 for a
segment reservation of S2. If the train has not obtained the segment reservation
when it passes the brake point(B.P.), the TCC brakes the train. It may proceed
when it has obtained a segment reservation for S2.
The algorithm performed at every tick is shown in figure 11.10.
11.3 Switch box algorithm 81
The sensor process starts in state idle. First the state of the sensor (ac-
tive/inactive) is fetched. This value is compared to the last state. If it has
turned from active to inactive, a train has just passed it.
If a train has just passed, the following will happen:
• If the SB at the sensor is an end SB and the train has driven into the
ESA, the SB sends a line dereservation message to the single line guard
at the opposite end of the single line.
To see illustrations of all these events please refer to section 11.1.1: “A sample
scenario”.
The switch box algorithm is explained through the state chart diagram in figure
11.13. Four of the states (all except Idle and done) are decomposed in separate
state chart diagrams and are described in the following.
• If the response is positive (OK) the SB prepares the first segment of the
single line (see section 11.3.7).
Glossary
This chapter presents a glossary that uses figure 12.1 as basis for the explaina-
tion of terms. The figure shows a part of a railway line. The circles denotes
switch boxes (SBs) and the lines denotes segments. The dots denotes that more
segments could be placed here (but no junctions).
Signal ticks Signal ticks denotes the number of seconds the signal at a crossing
is turned on before the barriers begin to close. In section 9.4 signal ticks
are shown in the state diagram as signals only.
Barrier ticks Barrier ticks denotes the number of seconds it takes for the
barriers at a crossing to either close or open. In section 9.4 barrier ticks
are shown in the state diagram as bars moving.
Chapter 13
GUI design
This chapter briefly describes the overall view of graphical user interface (GUI)
without going into details. The design conforms with the simulator requirements
described in chapter 7.
All the figures showing the GUI designs can be found in appendix A.
Figure A.1 shows the design of the train simulator. The two menus are shown
as they would appear when they are expanded.
The figure shows how the layout of the railway line are placed in the top. The
ESAs are shown as green rectangles. SBs are shown as circles, segments as lines,
and trains as colored pentagons placed on segments.
At a junction both branch segments are shown and the position of the coherent
points are shown using small colored rectangles above and below it. A green
rectangle denotes that the point is positioned at the branch segment near the
rectangle. Red means that the point is at the opposite branch and orange means
that the point is in an intermediate position.
The crossings are shown as two parallel vertical lines enclosing a SB (circle).
The colored rectangles (green, orange or red) above and below the crossing show
whether the barriers are closed or not. Red means that they are open, orange
that they are moving, and red that they are closed.
Below the layout of the railway line, rows of buttons are showed. These corre-
sponds to the entities of the railway line. When one of the buttons is pressed the
static, dynamic and control properties of the selected entity are showed below
the buttons.
94 GUI design
This chapter lists the assumptions and invariants identified for the system to
work. This list of invariants and assumptions is a summary of the decisions
made in chapters 10 and 9.
1. It is assumed that TCCs and SBCCs can communicate using some existing
communication service like a GSM network.
2. It is assumed that a TCC knows it’s current position by either measuring
length from last station or using GPS.
3. It is assumed that trains cannot collide when inside and ESA.
4. It is assumed that SBs have some interface to existing sensory equipment
on the track.
5. The distance from a segment border to a reservation point must be less
than the length of the segment (rp < [Link])
6. The brake point must be closer to the segment border than the reservation
point (rp > bp).
7. The train must not be on two segments when crossing a reservation point
(rp < [Link] − [Link])
8. At the most, a train can be on two segments at a time. This means that the
train must be shorter than any segment ([Link] < [Link]).
9. The length of the shortest train must be longer than the largest possible
collision detection error (scol < [Link] )
10. A train must be able to stop before entering the next segment when it
starts braking at the brake point. Therefore this length has to be longer
than the max brake length + the max simulation error made by discrete
time updates (bp > sbrk + serr ).
96 Assumptions and invariants
11. A train must be able to brake entirely in an ESA ([Link] > bp).
12. The TCC must handle the error made by discrete time updates (vtrain +
verr < vmax )
Chapter 15
This chapter briefly lists the method used to develop the model in the following
chapters. This is not a general description of transformation of RSL models so
all trivial steps are left out and only changes specific to this system / model are
listed.
For a model-specific description of the modules, their function, and the devel-
opment of the model in this project please refer to chapter 16.
For a more detailed and general description of RSL model transformations /
refinements please refer to appendix B.
The model is constructed to satisfy two conditions:
1. Suitable for easy translation into JAVA. Therefore the use of RSL spe-
cialties like subtypes - which are not directly implementable in JAVA - is
minimized as much as possible.
Figure 15.1 shows an illustration of the schemes of the initial model. The arrows
indicate which schemes are parameterized by other schemes.
15.1.2 Types
A Types module is defined which contains all common types for all modules.
The types module also contains utility functions that only operates on types
defined in the Types module itself. All other modules is parameterized by this
module.
15.1.3 Statics
type
Configuration
value
conf : Configuration
value
obsi : Tj × .. × Configuration → Tn
value
is wf : Configuration → Bool
is wf(con) ≡ p(..,obsi (..,con))
axiom
[ conf is wf ]
is wf(conf)
15.1.4 Dynamics
• The type of interest contains the composite state of the entire physical
system.
type
State
value
initState : State
value
obsi : Tk × .. × State → Tn ,
geni : Tk × .. × Tn × State → State
value
is wf : State × [Link] → Bool
is wf(s,con) ≡ [Link] wf(con) ∧ p(..,obsi (..,s))
• Some requirements for the initial state of the system are - like the well-
formedness predicate - defined as a predicate based on the observer func-
tions. This predicate includes the wellformedness requirements. This also
needs a configuration as input.
value
init req : State × [Link] → Bool
init req(s,con) ≡ is wf(s,con) ∧ p(..,obsi (..,s))
value
safe : State × [Link] → Bool
safe(s,con) ≡ is wf(s,con) ∧ p(..,obsi (..,s))
15.1 Initial specification 101
axiom
[ obsi genj ]
obsi (..,genj (..,s)) ≡ val expr
pre precondj (...)
axiom
[ wf pres geni ]
∀ s : State,
con : [Link] •
is wf(s,con) ∧ precondi (..) ⇒ is wf(geni (..,s)))
• An axiom is added requiring the initial state to satisfy the initial state
requirements. The constant [Link] is used as parameter.
axiom
[ init state req ]
init req(initStat,[Link])
15.1.5 Control
type
ControlState
value
initControlState : ControlState
102 RSL modelling method summary
value
obsi : Tk × .. × ControlState → Tn ,
geni : Tk × .. × Tn × ControlState → ControlState
value
is wf : ControlState × [Link] × [Link] → Bool
is wf(cs,ds,con) ≡ [Link] wf(ds,con) ∧ p(..,obsi (..,cs))
value
consistent : ControlState × [Link] × [Link] → Bool
consistent(cs,ds,con) ≡ is wf(cs,ds,con) ∧ p(..,obsi (..,cs))
• A predicate init req defines the requirements for the initial control state.
value
init req : ControlState × [Link] × [Link] → Bool
init req(cs,ds,con) ≡ is wf(cs,ds,con) ∧ p(..,obsi (..,cs))
• An axiom is added stating that the initial state must satisfy the init req
predicate.
axiom
init req(initControlState,[Link],[Link])
axiom
[ obsi genj ]
∀ cs : ControlState •
obsi (..,genj (..,cs)) ≡ val expr
pre precondj (..)
15.2 Type decomposition 103
• An axiom is added for each generator stating that all generators must
preserve wellformedness if the preconditions are satisfied.
axiom
[ wf pres geni ]
∀ cs : ControlState,
ds : [Link],
con : [Link] •
is wf(cs,ds,con) ∧ precondi (..,cs) ⇒
is wf(geni (..,cs),ds,con))
15.2.2 Statics
object
O1 : Sub1 ,
O2 : Sub2
type
Configuration = O1 .T1 × O2 .T2
• The actual configuration value in Statics, which did not have a value
before, is now given a concrete value being the product of the configuration
instance values in the new modules.
value
conf : Configuration = (O1 .confT1 , O2 .confT2 )
• All functions in Statics, that also exist in one of the new modules, are
changed so that they call the similar functions in the new modules. All
other functions in the decomposed statics module are left unchanged. This
rule does apply to is wf and init req which are moved to the appropriate
sub schemes.
value
obs1 : .. × Configuration → ..
obs1 (..,(t1 ,t2 )) ≡
O1 .obs1 (..,t1 )
value
is wf : Configuration → Bool
is wf((t1 ,t2 )) ≡
O1 .is wf(t1 ) ∧
O2 .is wf(t2 ) ∧
p1 (t1 ,t2 ) ∧
...
15.2.3 Dynamics
• One difference though is that dynamics also has a init req predicate. It
is handled as the is wf predicate in statics, so it becomes a conjunction
of the corresponding functions in the sub modules.
value
init req : State × [Link] → Bool
init req((t1 ,t2 ),con) ≡
[Link] wf(con) ∧
O1 .is wf(t1 ) ∧
O2 .is wf(t2 )
15.2.4 Control
Control is in this case decomposed a little differently than the statics and dy-
namics schemes. In these schemes each sub module represented a collection of
entities contributing to the entire state or configuration. Since the control sys-
tem is distributed, each controlling entity is modelled by having its own module.
• To model the many different entity states a map is created for each type of
controlling entity (TCC, SB) to contain all the entity states of that type.
The ControlState is then a product of these state maps.
object
CE1 : ControlEntity1 ,
CE2 : ControlEntity2
type
ControlState = CE1 Map × CE2 Map
• Like in the Statics scheme the sub modules have their own initial value
which must satisfy the init req predicate. But another predicate is needed
ensuring that all states in the maps are initially the initial values from the
sub schemes.
value
is ce1 init : ControlState → Bool
is ce1 init((ce1 map,ce2 map)) ≡
(
∀ state : CE1 .State •
state ∈ rng(ce1 map) ⇒ state = CE1 .initState
)
• And then the predicate ensuring that all states satisfy the init req()
predicate.
value
all ce1 initReq : ControlState → Bool
all ce1 initReq((ce1map,ce2map)) ≡
(
∀ state : [Link] •
state ∈ rng(ce1map) ⇒ [Link] req(state)
)
15.4.1 Statics
The statics module is made imperative. This means that variables are intro-
duced in all sub modules containing the type of interest.
• The variables are initialized with the constant which where defined to
represent the actual configuration of the module.
15.4 Imperative transformation 107
type
T1
value
confT1
variable
v T1 := confT1
axiom
[ initial ]
initialise post is wf()
15.4.2 Dynamics
Dynamics is transformed exactly like Statics with the exception that it is the
init req() that is used in the axiom. This is because the dynamics module also
has some requirements for the initial state and these include the is wf predicate.
Beside that, the variables are initialized with the initial state.
15.4.3 Control
Variables are also introduced in the sub modules of the Control module. One
difference is though that the sub modules only contain a variable with one single
state each.
• Object arrays are created to represent the many control entities in the
system. Each control entity has their own state stored in variables. The
object arrays are now used instead of the maps which where necessary
before.
object
CE1 [ n : CE1 Index ] : ControlEntity1 ,
CE2 [ n : CE2 Index ] : ControlEntity2
• The types CE1 Index and CE2 Index are created together with two maps to
be able to map from an array index to an entity ID.
108 RSL modelling method summary
type
CE1 Index = {| n : Nat • n > 0 ∧ n ≤ card T.ce1 IDSet |},
CE2 Index = {| n : Nat • n > 0 ∧ n ≤ card T.ce2 IDSet |}
value
ce1 Index : T.CE1 ID →
m Nat,
ce2 Index : T.CE2 ID →
m Nat
axiom
[ initial ]
initialise post initReq()
Initial Model
This chapter concerns the development of the initial abstract RSL model. First
a section gives an overview of the model module structure. Then a section
briefly describes how material produced in the analysis and design sections is
used in creating the model.
The following sections describe the detailed step by step development of the
initial model. This development follows the modelling method described in
chapter 15. The entire model can be found in appendix F.
It should be noted that basic observers at this level are left unspecified because
the main data structures are abstract sorts at this level of development.
Types a common types module which enables all modules to use same types.
Statics defines the physical parts of the system as segment, switch box, end
station area, sensor, point, train, crossing and the physical relationship
between these.
Dynamics defines the dynamic part (physical states) of the entities defined in
Statics.
Control defines entities for controlling the physical domain. The entities de-
fined are switch box control computer (SBCC) and train control computer
110 Initial Model
This section briefly lays out what was produced in the analysis chapters and
how this is implemented in the model.
Algorithms / UML state charts These are used in the main processes or
functions for the entities in the system. They are the processes which are
called when the system is updated by the tick function (The tick principle
is briefly described in section 5.3).
16.3 Types
The Types module contains all common types for all modules and some utility
functions.
In the following the most important types is described. None of the utility
functions is described. The entire Types module can be found in appendix
F.1.1.
16.3.1 Tick
A type Tick and a constant tick interval of this type is defined to specify the
interval of seconds between (and the size of) each time update. This value
is used in some predicates which ensure that the interval is small enough for
collisions and brake point exceedings to be detected.
type
Tick = real
value
tick interval : Tick
16.3.2 Ends
The railway line is defined to have two ends, that is the high and the low end.
The direction from low to high is called up and the opposite direction is called
down:
type
End == HIGH | LOW,
Direction == UP | DOWN
The four entities ESA, SB, segment and train are all represented by their ID.
For the two ESAs the ID is just the end at which the ESA is located. The three
other entities are defined as an ID, which is a sort, but limited through the use
of a subtype. The functions sbIDLimit, segIDLimit and trainIDLimit checks if
an ID is a valid ID for a SB, segment or train.
type
ID,
ESAID = End,
112 Initial Model
16.3.4 SB types
The SBSegment type is defined to hold the ”place(s)” in the railway line after
a SB. This can be a plain segment (seg), the two branch segments at a point
(point) or an ESA (esa).
The SBType defines the type of a SB.
type
SBSegment == seg(getSeg : SegmentID) |
point(getUpSeg : SegmentID, getDownSeg : SegmentID) |
esa(getESA : ESAID),
SBType == POINTSB | ENDSB | CROSSINGSB | PLAINSB
A number of types define the position or status of points, barriers, signals and
sensors.
type
PointPosition == UP | DOWN | MOVINGUP | MOVINGDOWN,
BarrierPosition == UP | DOWN | MOVINGUP | MOVINGDOWN,
SignalStatus == ON | OFF,
SensorStatus == ACTIVE | INACTIVE
The Location type defines the location of a train, which is either in an ESA
or on a Segment. The SegmentPosition type defines the precise position in the
railway line. The TrainPosition type defines both the front- and rear position
of a train.
type
Location == isESA(getESA : ESAID) | isSeg(getSeg : SegmentID),
TrainPosition :: frontPos : SegmentPosition ↔ setFrontPos
rearPos : SegmentPosition ↔ setRearPos,
16.4 Statics 113
16.3.7 Reservation
The Reservation type defines a reservation for a certain train in a certain direc-
tion. The HasRes type defines either the existence of a particular reservation
or the absence of a reservation.
type
HasRes == res(Reservation) | noRes,
Reservation == mk res(getTrain : TrainID, getDir : Direction)
16.3.8 Messages
A number of message types etc. are defined to be used in the control system,
so that SBs and trains can communicate with each other.
type
Message = TCCMsg | SBCCMsg,
TCCMsg == segReq(Reservation),
SBCCMsg = SBCCResMsg | SBCCDeResMsg | SBCCRespMsg,
SBCCResMsg == lineBranchReq(Reservation),
SBCCDeResMsg == lineBranchDeRes | lineDeRes
| branchDeRes,
SBCCRespMsg = LineBranchResp | SegmentResp,
LineBranchResp == lineBranchResp(getRes : Reservation, isPos : Bool),
SegmentResp == segResp(isPos : Bool),
16.4 Statics
This section describes the Statics module.
114 Initial Model
The Configuration type is defined as the type of interest. In this initial specifi-
cation it is a sort. A constant denoting the actual configuration is also defined.
type
Configuration
value
conf : Configuration
16.4.2 Observers
A number of basic observers are defined and shown below grouped after which
entity they concern.
value
∼
getESASB : [Link] × Configuration → [Link],
∼
getESALength : [Link] × Configuration → [Link],
esaExistsInConf : [Link] × Configuration → Bool
Switch boxes
value
∼
getSBSeg : [Link] × [Link] × Configuration → [Link],
∼
getSBType : [Link] × Configuration → [Link],
sbExistsInConf : [Link] × Configuration → Bool
Segments
∼
getSegSB : [Link] × [Link] × Configuration → [Link],
∼
getSegLength : [Link] × Configuration → [Link],
∼
getSegMaxSpeed : [Link] × Configuration → [Link],
segExistsInConf : [Link] × Configuration → Bool
Trains
value
∼
getTrainLength : [Link] × Configuration → [Link],
∼
getTrainMaxSpeed : [Link] × Configuration → [Link],
∼
getTrainMaxAcc : [Link] × Configuration → [Link],
∼
getTrainMaxDeAcc : [Link] × Configuration → [Link],
trainExistsInConf : [Link] × Configuration → Bool
value
∼
getResPoint : Configuration → [Link],
∼
getBrakePoint : Configuration → [Link]
getResPoint returns the reservation point which is common for all segments
getBrakePoint returns the brake point which is common for all segments
116 Initial Model
Some derived observers are defined in terms of the basic observers but they are
not shown here. The entire module can be found in appendix F.1.2.
16.4.4 Wellformedness
The wellformedness predicate is defined as:
value
is wf : Configuration → Bool
is wf(con) ≡
sbs is wf(con) ∧
segs is wf(con) ∧
esas is wf(con) ∧
trains is wf(con) ∧
composed is wf(con)
sbsHaveConf
Each SB must have a configuration and the reservation- and brake point must
be greater than zero:
value
sbsHaveConf : Configuration → Bool
sbsHaveConf(con) ≡
(
(∀ seg : [Link] •
sbExistsInConf(seg,con)) ∧
getResPoint(con) > 0.0 ∧
getBrakePoint(con) > 0.0
)
getSBSeg diff
The segments next to a SB are different in both directions (UP and DOWN).
I.e. the line is not circular
value
getSBSeg diff : Configuration → Bool
getSBSeg diff(con) ≡
(
∀ sb : [Link] •
getSBSeg(sb,[Link],con) 6= getSBSeg(sb,[Link],con)
)
getSBSeg point wf
value
getSBSeg point wf : Configuration → Bool
getSBSeg point wf(con) ≡
(
∀ sb : [Link],
seg1,seg2 : [Link],
dir : [Link] •
[Link](seg1,seg2) = getSBSeg(sb,dir,con) ⇒
seg1 6= seg2
)
getSBSeg injective
value
getSBSeg injective : Configuration → Bool
getSBSeg injective(con) ≡
(
∀ sb1, sb2 : [Link],
dir : [Link] •
sb1 6= sb2 ⇒
getSBSeg(sb1,dir,con) 6= getSBSeg(sb2,dir,con)
)
getSBSegType wf
value
getSBSegType wf : Configuration → Bool
getSBSegType wf(con) ≡
(
∀ sb : [Link] •
case getSBType(sb,con) of
[Link] → (∃! dir : [Link], esa : [Link] •
esa = T.dir2End(dir) ∧
getSBSeg(sb,dir,con) = [Link](esa)),
[Link] → (∃! dir : [Link],
seg1,seg2 : [Link] •
getSBSeg(sb,dir,con) = [Link](seg1,seg2)),
[Link] → (∀ dir : [Link] •
∃ seg : [Link] •
getSBSeg(sb,dir,con) = [Link](seg)),
[Link] → (∃! dir : [Link] •
∃ seg : [Link] •
getSBSeg(sb,dir,con) = [Link](seg))
end
)
segsHaveConf
value
segsHaveConf : Configuration → Bool
segsHaveConf(con) ≡
(
∀ seg : [Link] •
segExistsInConf(seg,con)
)
16.4 Statics 119
getSegSB injective
The SB at the end of a segment is different for two different segments or they
are the same in both directions (being branches):
value
getSegSB injective : Configuration → Bool
getSegSB injective(con) ≡
(
∀ seg1, seg2 : [Link],
dir : [Link] •
seg1 6= seg2 ⇒
(
getSegSB(seg1,dir,con) 6= getSegSB(seg2,dir,con)
)
∨
(
getSegSB(seg1,[Link],con) = getSegSB(seg2,[Link],con) ∧
getSegSB(seg1,[Link],con) = getSegSB(seg2,[Link],con)
)
)
brakeResPoint wf
value
brakeResPoint wf : Configuration → Bool
brakeResPoint wf(con) ≡
getResPoint(con) > getBrakePoint(con)
esasHaveConf
value
esasHaveConf : Configuration → Bool
esasHaveConf(con) ≡
(
∀ esa : [Link] •
esaExistsInConf(esa,con)
)
120 Initial Model
trainsHaveConf
value
trainsHaveConf : Configuration → Bool
trainsHaveConf(con) ≡
(
∀ t : [Link] •
trainExistsInConf(t,con)
)
getESASBSeg wf
Given an ESA, from the coherent END SB the next SBSegment directed against
the ESA must be the ESA itself:
value
getESASBSeg wf : Configuration → Bool
getESASBSeg wf(con) ≡
(
∀ esa : [Link] •
getSBSeg(getESASB(esa,con),T.end2Dir(esa),con) = [Link](esa)
)
getSBSeg getSegSB wf
value
getSBSeg getSegSB wf : Configuration → Bool
getSBSeg getSegSB wf(con) ≡
(
∀ sb : [Link], dir : [Link], seg : [Link] •
seg ∈ [Link](getSBSeg(sb,dir,con)) ⇒
getSegSB(seg,[Link](dir),con) = sb
)
value
seg train length wf : Configuration → Bool
16.4 Statics 121
value
esa train length wf : Configuration → Bool
esa train length wf(con) ≡
(
∀ esa : [Link], t : [Link] •
getESALength(esa,con) > getBrakePoint(con) + getTrainLength(t,con)
)
brakePoint wf
If a train starts to brake at the brakepoint it must be able to stop entirely before
entering the next segment
resPoint wf
When a train reach the break point it must be entirely on a single segment and
the brake point must be smaller than the length of any segment:
value
resPoint wf : Configuration → Bool
resPoint wf(con) ≡
122 Initial Model
(
∀ t : [Link], seg : [Link],
tlen, slen, resPoint, brakePoint : [Link] •
tlen = getTrainLength(t,con) ∧
slen = getSegLength(seg,con) ∧
resPoint = getResPoint(con) ∧
brakePoint = getBrakePoint(con)
⇒
slen > (resPoint + tlen) ∧
brakePoint < slen
)
collisions detectable
This predicate ensures that the time update interval (tick ) in the simulator is
sufficiently small so that frontal collisions between two trains moving at top
speed is detected.
For the calculations associated with this predicate please refer to section 10.3.1.
16.5 Dynamics
This section describes the Dynamics module.
The State type is defined as the type of interest. In this initial specification it
is a sort. A value containing the initial state is also defined.
type
State
value
initState : State
16.5 Dynamics 123
A number of basic observers and generators are defined and shown below grouped
after which entity they concern.
Point
value
∼
getPointPosition : [Link] × State × [Link] → [Link],
∼
setPointPosition : [Link] × [Link] × State × [Link] → State,
Crossing
value
∼
getBarrierPosition : [Link] × State × [Link] → [Link],
∼
getSignalStatus : [Link] × State × [Link] → [Link],
∼
setBarrierPosition : [Link] × [Link] × State × [Link] → State,
∼
setSignalStatus : [Link] × [Link] × State × [Link] → State
Sensor
Train
value
getTrainAcc : [Link] × State → [Link],
getTrainSpeed : [Link] × State → [Link],
getTrainPosition : [Link] × State → [Link],
getTrainDirection : [Link] × State → [Link],
∼
setTrainAcc : [Link] × [Link] × State × [Link] → State,
∼
setTrainSpeed : [Link] × [Link] × State × [Link] → State,
∼
setTrainPosition : [Link] × [Link] × State × [Link] → State,
∼
setTrainDirection : [Link] × [Link] × State → State
value
∼
tick : [Link] × [Link] × State → State
tick(tick,con,s) ≡
let
s = tickPoints(tick,con,s),
s = tickCrossings(tick,con,s),
s = tickTrains(tick,con,s)
in
s
end
16.5 Dynamics 125
The tick function just ticks every point, crossing and train after each other.
Below these three functions are described.
Ticking points
The tickPoints finds all the point IDs (SB IDs for point SBs) and then calls the
pointProcess function with the set of the point IDs as parameter.
value
∼
tickPoints : [Link] × [Link] × State → State
tickPoints(tick,con,s) ≡
let
points = { p | p : [Link] • [Link](p,con) = [Link] }
in
pointProcess(points,tick,con,s)
end
The pointProcess method handles one point at the time. It takes a point ID
from the set of point IDs and uses this as argument to the updatePoint function.
After updatePoint has been executed pointProcess calls itself recursively after
removing the mentioned point ID from the set of point IDs. The function
terminates when all point IDs have been processed, i.e. when the set of point
IDs is empty.
updatePoint finds the new position of the point. If the point is moving either
up or down respectively the point either remains the same or switches up or
down respectively. This simulates that it takes some amount of time to switch
a point. When the model is made concrete point ticks are introduced which
specifies how many seconds it takes to switch the point.
The states of a point are modelled as a state machine in figure 9.4 in section
9.5.
value
∼
pointProcess : [Link]-set × [Link] × [Link] × State → State
pointProcess(points,tick,con,s) ≡
if(points = {})
then
s
else
let
p : [Link] • p ∈ points,
points = points \ {p},
s = updatePoint(p,tick,con,s)
in
pointProcess(points,tick,con,s)
end
end
pre [Link](points,con),
126 Initial Model
∼
updatePoint : [Link] × [Link] × [Link] × State → State
updatePoint(p,tick,con,s) ≡
let
pp = getPointPosition(p,s,con)
in
case pp of
[Link] → s de setPointPosition(p,[Link],s,con),
[Link] → s de setPointPosition(p,[Link],s,con),
→s
end
end
pre [Link](p,con) = [Link]
Ticking crossings
The tickCrossings finds all the crossing IDs (SB IDs for crossing SBs) and then
calls the crossingProcess function with the set of the crossing IDs as parameter.
value
∼
tickCrossings : [Link] × [Link] × State → State
tickCrossings(tick,con,s) ≡
let
crossings = { c | c : [Link] • [Link](c,con) = [Link] }
in
crossingProcess(crossings,tick,con,s)
end
The crossingProcess function handles one crossing at the time. It takes a cross-
ing ID from the set of crossing IDs and uses this as argument to the updateCross-
ing function. After updateCrossing has been executed crossingProcesses calls
itself recursively after removing the mentioned crossing ID from the set of cross-
ing IDs. The function terminates when all crossing IDs have been processed,
i.e. when the set of crossing IDs is empty.
The updateCrossing function handles the change in the state of a crossing that
has just begun to close og to open. If the crossing is open (barriers is up and
signals is off) or if the crossing is closed (barriers is down and signals is off)
then updateCrossing does not change the state of the crossing.
The first step in opening or closing the crossing is always performed by the SB
controlling the crossing when it prepares the segment the train has requested a
reservation for and when the train has passed the crossing.
The first step in closing the crossing is to turn on the signals. Then after an
amount of time updateCrossing sets the barriers to be moving down. This is
modelled by having an internal choice between doing nothing and setting the
barriers to be moving down. It simulates that the signals are turned on a while
before the barriers start to move down. Likewise, if the barriers are moving
16.5 Dynamics 127
value
∼
crossingProcess : [Link]-set × [Link] × [Link] × State → State
crossingProcess(crossings,tick,con,s) ≡
if(crossings = {})
then
s
else
let
c : [Link] • c ∈ crossings,
crossings = crossings \ {c},
s = updateCrossing(c,tick,con,s)
in
crossingProcess(crossings,tick,con,s)
end
end
pre [Link](crossings,con),
∼
updateCrossing : [Link] × [Link] × [Link] × State → State
updateCrossing(cr,tick,con,s) ≡
let
bp = getBarrierPosition(cr,s,con),
ss = getSignalStatus(cr,s,con)
in
case bp of
[Link] →
(
if(ss = [Link])
then
s de
setBarrierPosition(cr,[Link],s,con)
else
s
end
),
[Link] →
(
s de
(
let
bp = setBarrierPosition(cr,[Link],s,con)
in
setSignalStatus(cr,[Link],s,con)
128 Initial Model
end
)
),
[Link] → s,
[Link] → s de setBarrierPosition(cr,[Link],s,con)
end
end
pre [Link](cr,con) = [Link]
Ticking trains
The tickTrains finds all the train IDs and then calls the trainProcess function
with the set of the train IDs as parameter.
value
∼
tickTrains : [Link] × [Link] × State → State
tickTrains(tick,con,s) ≡
let
trains = { t | t : [Link]}
in
trainProcess(trains,tick,con,s)
end
The trainProcess method handles one train at the time. It takes a train ID from
the set of train IDs and uses this as argument to the unspecified updateTrain
function. updateTrain calculates the new position of the train from the current
position, speed and acceleration.
value
∼
trainProcess : [Link]-set × [Link] × [Link] × State → State
trainProcess(trains,tick,con,s) ≡
if(trains = {})
then
s
else
let
t : [Link] • t ∈ trains,
trains = trains \ {t},
s = updateTrain(t,tick,con,s)
in
trainProcess(trains,tick,con,s)
end
end,
∼
updateTrain : [Link] × [Link] × [Link] × State → State
16.5 Dynamics 129
A number of derived observers and generators are defined in terms of the basic
observers and generators but they are not shown here, besides the wellformed-
ness functions et al. below. The entire module can be found in appendix F.1.3.
16.5.5 Wellformedness
value
is wf : State × [Link] → Bool
is wf(s,con) ≡
allStatesExists(con,s),
allTrainStatesExist
value
allTrainStatesExist : State → Bool
allTrainStatesExist(s) ≡
(
∀ trainID : [Link] •
trainStateExists(trainID,s)
/∗ Tells if a train has a state in the system ∗/
trainStateExists
) : [Link] × State → Bool
train pos wf
Front and rear position of a train must be exactly ’train length’ apart:
130 Initial Model
value
∼
train pos wf : [Link] × State → Bool
train pos wf(con,s) ≡
(
∀ t : [Link] •
train pos ok(t,getTrainPosition(t,s),s,con)
),
∼
train pos ok : [Link] × [Link] × State × [Link] → Bool
train pos ok(t,tp,s,con) ≡
(
let
[Link] TrainPosition(posFront,posRear) = tp
in
([Link](posFront,posRear,con) = [Link](t,con)) ∧
train pos dir ok(getTrainDirection(t,s),tp,s,con)
end
)
allCrossingStatesExist
value
allCrossingStatesExist : [Link] × State → Bool
allCrossingStatesExist(con,s) ≡
(
∀ cr : [Link] •
[Link](cr,con) = [Link] ⇒
crossingStateExists(cr,s,con)
),
/∗ Tells if a crossing has a state in the system ∗/
crossingStateExists : [Link] × State × [Link] → Bool
allPointStatesExist
value
allPointStatesExist : [Link] × State → Bool
allPointStatesExist(con,s) ≡
(
∀ p : [Link] •
[Link](p,con) = [Link] ⇒
pointStateExists(p,s,con)
), /∗ Tells if a point has a state in the system ∗/
pointStateExists : [Link] × State × [Link] → Bool
16.5 Dynamics 131
allSensorStatesExist
value
allSensorStatesExist : State → Bool
allSensorStatesExist(s) ≡
(
∀ sen : [Link] •
sensorStateExists(sen,s)
),
/∗ Tells if a sensor has a state in the system ∗/
sensorStateExists : [Link] × State → Bool
∼
safe : State × [Link] → Bool
safe(s,con) ≡
is wf(s,con) ∧
noCollisions(con,s) ∧
trainPosPossible(con,s) ∧
pointsSafe(con,s) ∧
crossingsSafe(con,s)
Notice that a safe state is also wellformed. The used functions, except is wf is
explained shortly in the following.
noCollisions
The position of a train may not overlap with the position of other trains. This
predicate is used both for the safe predicate and as precondition for the Dynam-
[Link]().
value
∼
noCollisions : [Link] × State → Bool
noCollisions(con,s) ≡
(
∀ t : [Link] •
∼trainPositionOccupied(t,getTrainPosition(t,s),s,con)
)
132 Initial Model
trainPosPossible
Trains cannot end up on same segment driving in opposite directions away from
each other.
If two trains are on same segment driving in opposite directions then the train
driving up must be lower on the line than the train driving down:
value
∼
trainPosPossible : [Link] × State → Bool
trainPosPossible(con,ds) ≡
(
∀ t1,t2 : [Link], segs : [Link]-set,
tp1,tp2 : [Link], seg : [Link] •
commonSegs(t1,t2,ds) 6= {} ∧
(tp1,tp2) = (getTrainPosition(t1,ds),getTrainPosition(t1,ds)) ∧
getTrainDirection(t1,ds) 6= getTrainDirection(t2,ds) ∧
getTrainDirection(t1,ds) = [Link]
⇒
[Link]([Link](tp1),[Link](tp2),con)
)
pointsSafe
If the train is located upon a junction, the point must be connected to the
branch, on which the train is located:
value
∼
pointsSafe : [Link] × State → Bool
pointsSafe(con,ds) ≡
(
∀ sb : [Link], t : [Link], seg : [Link] •
trainOnJunction(t,sb,con,ds) ∧
trainOnSegment(t,seg,con,ds) ∧
[Link](seg,con) ⇒
pointConnected(sb,seg,ds,con)
)
crossingsSafe
value
∼
crossingsSafe : [Link] × State → Bool
crossingsSafe(con,s) ≡
(
∀ sb : [Link] •
[Link](sb,con) = [Link] ∧
16.5 Dynamics 133
trainOnSensor(sb,con,s) ⇒
getBarrierPosition(sb,s,con) = [Link]
)
The initial requirement specifies some requirements to how the physical state
must look like initially. An axiom is stated to make sure that the requirements
are satisfied:
value
∼
init req : State × [Link] → Bool
init req(s,con) ≡
is wf(s,con) ∧
allTrainsInESA(s) ∧
allTrainsFacingLine(s) ∧
allTrainsStopped(s) ∧
allBarriersUp(con,s) ∧
allPointsNotShifting(con,s)
axiom
[ wellformedness ]
init req(initState,[Link])
Notice that the initial state must be wellformed. The used functions, except
is wf is explained shortly in the following.
allTrainsInESA
value
∼
allTrainsInESA : State → Bool
allTrainsInESA(s) ≡
(
∀ t : [Link] •
trainInESA(t,s)
)
allTrainsFacingLine
value
∼
allTrainsFacingLine : State → Bool
allTrainsFacingLine(s) ≡
134 Initial Model
(
∀ t : [Link], esa : [Link] •
[Link](esa) = [Link]([Link](getTrainPosition(t,s))) ∧
(esa = [Link] ⇒ getTrainDirection(t,s) = [Link]) ∧
(esa = [Link] ⇒ getTrainDirection(t,s) = [Link])
)
allTrainsStopped
value
∼
allTrainsStopped : State → Bool
allTrainsStopped(s) ≡
(
∀ t : [Link] •
getTrainSpeed(t,s) = 0.0 ∧
getTrainAcc(t,s) = 0.0
)
allBarriersUp
value
∼
allBarriersUp : [Link] × State → Bool
allBarriersUp(con,s) ≡
(
∀ sb : [Link] •
[Link](sb,con) = [Link] ⇒
getBarrierPosition(sb,s,con) = [Link]
)
allPointsNotShifting
value
∼
allPointsNotShifting : [Link] × State → Bool
allPointsNotShifting(con,s) ≡
(
∀ sb : [Link] •
[Link](sb,con) = [Link] ⇒
getPointPosition(sb,s,con) ∈ { [Link], [Link] }
)
16.5 Dynamics 135
axiom
[ getPointPosition setPointPosition ]
∀ s : State, p1,p2 : [Link], pp : [Link],
con : [Link] •
getPointPosition(p1,setPointPosition(p2,pp,s,con),con) ≡
if(p1 = p2)
then
pp
else
getPointPosition(p1,s,con)
end
pre [Link](p1,con) = [Link] ∧
[Link](p2,con) = [Link] ∧
pointStateExists(p1,s,con) ∧
pointStateExists(p2,s,con) ∧
∼trainOnJunction(p2,con,s)
If the observer and generator gets the same point (switch box ID) as argument,
the observer returns the same point position as has been input to the generator.
This reflects the intended behavior, that the generator only changes the position
of the point it gets as argument.
axiom
[ gen wf setPointPosition ]
∀ p : [Link], pp : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](p,con) = [Link] ∧
∼trainOnJunction(p,con,s)
⇒
is wf(setPointPosition(p,pp,s,con),con)
16.6 Control
This section describes the Control module.
The ControlState type is defined as the type of interest. In this initial specifi-
cation it is a sort. A value containing the initial control state is also defined.
type
ControlState
value
initControlState : ControlState
A number of basic observers and generators are defined and shown below grouped
after which entity they concern.
SBCC
value
∼
getSBCCLineRes : [Link] × ControlState → [Link],
∼
getSBCCBranchRes : [Link] × ControlState → [Link],
∼
setSBCCLineRes : [Link] × [Link] × ControlState → ControlState,
∼
setSBCCBranchRes : [Link] × [Link] × ControlState → ControlState,
∼
getLastSensorStatus : [Link] × ControlState → [Link],
∼
setLastSensorStatus : [Link] × [Link] × ControlState → ControlState,
∼
getNextSBCCMsg : [Link] × ControlState → [Link] × ControlState,
∼
storeSBCCMsg : [Link] × [Link] × ControlState → ControlState,
∼
setSBCCPrepRes : [Link] × [Link] × ControlState → ControlState,
∼
getSBCCPrepRes : [Link] × ControlState → [Link],
TCC
value
∼
hasTCCRes : [Link] × ControlState → Bool,
∼
setTCCRes : [Link] × Bool × ControlState → ControlState,
∼
isTCCRequesting : [Link] × ControlState → Bool,
∼
setTCCRequesting : [Link] × Bool × ControlState → ControlState,
∼
isTrainDecelerating : [Link] × ControlState → Bool,
∼
setTrainDecelerating : [Link] × Bool × ControlState → ControlState,
∼
hasPassedResPoint : [Link] × [Link] × [Link] → Bool,
∼
hasPassedBrakePoint : [Link] × [Link] × [Link] → Bool,
The control system is ticked just like the physical system. First the physical
system is ticked, then the control system is ticked. The tick function of the
control system looks like:
value
∼
tick : [Link] × ControlState × [Link] × [Link] →
(ControlState × [Link])
tick(tick,cs,ds,con) ≡
(
let
tSet = {t | t : [Link]},
sbSet = {sb | sb : [Link]},
(cs,ds) = tickTCCs(tSet,tick,cs,ds,con),
cs = tickSBCCs(sbSet,cs,ds,con)
in
(cs,ds)
end
)
The tick function first calls tickTCCs with a set of all train IDs as parameter.
Then it calls tickSBCCs with a set of all SB IDs as parameter. These functions
are described shortly in the following.
Ticking TCCs
The tickTCCs funtion takes one train ID out from the set of train IDs and calls
the tccProcess function with this train ID. After executing tccProcess, tickTCCs
calls itself recursively until all train IDs have been used.
value
∼
tickTCCs : [Link]-set × [Link] × ControlState × [Link] × [Link] →
(ControlState × [Link])
tickTCCs(tccSet,tick,cs,ds,con) ≡
if (tccSet = {}) then
(cs,ds)
else
let
tcc : [Link] • tcc ∈ tccSet,
tccSet = tccSet \ {tcc},
(cs,ds) = tccProcess(tcc,tick,cs,ds,con)
in
tickTCCs(tccSet,tick,cs,ds,con)
end
end
16.6 Control 139
The tccProcess function is called for every train (TCC). It follows the algorihtm
desribed in section 11.2 by sequentially calling the functions checkSpeed, clearRes
and handleRes.
checkSpeed checks that the speed of the train does not exceed the max allowed
for the segment and the train.
clearRes removes a reservation for a segment when the segment is left.
handlesRes makes sure that the train has a reservation for the segment it is
to enter. If it has not received a reservation in time the function brakes
the train.
value
∼
tccProcess : [Link] × [Link] × ControlState × [Link] × [Link] →
ControlState × [Link]
tccProcess(t,tick,cs,ds,con) ≡
let
(cs,ds) = checkSpeed(t,tick,cs,ds,con),
cs = clearRes(t,cs,ds),
(cs,ds) = handleRes(t,cs,ds,con)
in
(cs,ds)
end
Only the handleRes function is shown here. The two other functions can be
found in appendix F.1.4 along with the entire control module.
The handleRes function follows the algorithm described in 11.2.3 which is a part
of the TCC algorithm. If the train has passed the reservation point the TCC
request the proper SB for a reservation. If it has passed the brake point without
having received a reservation the TCC brakes the train.
value
∼
handleRes : [Link] × ControlState × [Link] × [Link] → ControlState × [Link]
handleRes(t,cs,ds,con) ≡
if(hasPassedResPoint(t,ds,con))
then
if(∼hasTCCRes(t,cs))
then
(cs,ds)
else
let
(cs,ds) = if(hasPassedBrakePoint(t,ds,con))
then decelerateTrain(t,cs,ds,con)
else (cs,ds) end
in
if(∼isTCCRequesting(t,cs))
then
tccRequestRes(t,cs,ds,con)
else
(cs,ds)
140 Initial Model
end
end
end
else
(cs,ds)
end
Ticking SBCCs
The tickSBCCs funtion takes one SB ID out from the set of SB IDs and calls the
sbccProcess function with this SB ID. After executing sbccProcess, tickSBCCs
calls itself recursively until all SB IDs have been used.
value
∼
tickSBCCs : [Link]-set × ControlState × [Link] × [Link] → ControlState
tickSBCCs(sbSet,cs,ds,con) ≡
if (sbSet = {}) then
cs
else
let
sbcc : [Link] • sbcc ∈ sbSet,
sbSet = sbSet \ {sbcc},
cs = sbccProcess(sbcc,cs,ds,con)
in
tickSBCCs(sbSet,cs,ds,con)
end
end,
The sbccProcess is called for every SB (SBCC). It follows the algorithm de-
scribed in section 11.3 by using the functions sensorProcess, prepareProcess and
sbccMsgProcess.
sensorProcess monitors the state of a sensor. If a train has passed the sensor,
it dereserves reservations in the proper end SBs/point SBs.
value
∼
sbccProcess : [Link] × ControlState × [Link] × [Link] → ControlState
sbccProcess(sb,cs,ds,con) ≡
let
cs = sensorProcess(sb,cs,ds,con)
in
if(isPreparing(sb,cs)) then
prepareProcess(sb,cs,ds,con)
else
16.6 Control 141
sbccMsgProcess(sb,cs,ds,con)
end
end
Only the sensorprocess function is shown here. Some of the functions sensor-
Process uses have not and is not shown here. They can be found in appendix
F.1.4 along with the entire control module.
The sensorProcess function follows the algorithm desribed in section 11.3.1
which is a part of the SB algorithm. It retrives and saves the state of the
sensor from the Dynamics module. If it has passed from active to inactive a
train has just passed. Then it dereserves the segment the train left, if it is a
end SB or point SB. The rest of the SBs does not store reservations.
value
∼
sensorProcess : [Link] × ControlState × [Link] × [Link] → ControlState
sensorProcess(sb,cs,ds,con) ≡
let
sState = [Link](sb,ds),
lastState = getLastSensorStatus(sb,cs),
cs = setLastSensorStatus(sb,sState,cs)
in
if((lastState = [Link]) ∧ (sState = [Link]))
then
let
ds = dePrepareSeg(sb,cs,ds,con)
in
if([Link](sb,con))
then
makeDeRes(sb,cs,ds,con)
else
cs
end
end
else
cs
end
end
16.6.4 Wellformedness
value
is wf : ControlState × [Link] × [Link] → Bool
is wf(cs,ds,con) ≡
[Link] wf(ds,con) ∧
tcc has state(cs) ∧
sbcc has state(cs)
142 Initial Model
The control system is wellformed when its associated physical system is well-
formed and a state exists for every TCC and SBCC.
value
tcc has state : ControlState → Bool
tcc has state(cs) ≡
(
∀ t : [Link] •
tccStateExists(t,cs)
)
value
sbcc has state : ControlState → Bool
sbcc has state(cs) ≡
(
∀ sb : [Link] •
sbccStateExists(sb,cs)
)
The control system and all its components must be consistent, e.g. the informa-
tion stored in the control system must reflect the physical world and unintended
states must not occur. Also the physical world must abide by the rules of the
control system.
value
consistent : ControlState × [Link] × [Link] → Bool
consistent(cs,ds,con) ≡
is wf(cs,ds,con) ∧
train on branch dir(ds,con) ∧
tcc hasRes passedResPoint(cs,ds,con) ∧
sbcc res wf(cs,con) ∧
position branch sbcc res wf(cs,ds,con) ∧
tcc res branch wf(cs,ds,con) ∧
position sl sbcc res wf(cs,ds,con) ∧
barrierPos signalStatus Consistent(ds,con)
16.6 Control 143
Notice that a consistent control state is also wellformed. The used functions,
except is wf, is explained in the following.
value
train on branch dir : [Link] × [Link] → Bool
train on branch dir(ds,con) ≡
(
∀ t : [Link], seg : [Link] •
[Link](t,con,ds) ∧
[Link](t,seg,con,ds) ∧
[Link](seg,con) ⇒
[Link](seg,con) = [Link](t,ds)
)
If a train has a reservation then it has passed the reservation point on the given
segment:
value
tcc hasRes passedResPoint : ControlState × [Link] × [Link] → Bool
tcc hasRes passedResPoint(cs,ds,con) ≡
(
∀ t : [Link] •
hasTCCRes(t,cs) ⇒ hasPassedResPoint(t,ds,con)
)
sbcc res wf
Only POINTSB and ENDSB may have line reservations. Only POINTSB may
have branch reservations:
value
sbcc res wf : ControlState × [Link] → Bool
sbcc res wf(cs,con) ≡
(
∀ sb : [Link] •
([Link](sb,con) ∈ {[Link], [Link]} ⇒
{getSBCCLineRes(sb,cs)} ∪ {getSBCCBranchRes(sb,cs)} = {[Link]})
∧
([Link](sb,con) = [Link] ⇒ getSBCCBranchRes(sb,cs) = [Link])
)
144 Initial Model
value
position branch sbcc res wf : ControlState × [Link] × [Link] → Bool
position branch sbcc res wf(cs,ds,con) ≡
(
∀ t : [Link],
sb : [Link],
tDir : [Link],
seg : [Link] •
tDir = [Link](t,ds) ∧
[Link](t,seg,con,ds) ∧
[Link](t,con,ds) ∧
[Link](seg,con) ∧
sb = [Link](seg,[Link](tDir),con)
⇒
getSBCCBranchRes(sb,cs) = [Link]([Link] res(t,tDir))
)
value
tcc res branch wf : ControlState × [Link] × [Link] → Bool
tcc res branch wf(cs,ds,con) ≡
(
∀ t : [Link],
seg : [Link],
trainDir : [Link],
guard1,guard2 : [Link],
res : [Link] •
[Link](t,seg,con,ds) ∧
[Link](t,con,ds) ∧
hasTCCRes(t,cs) ∧
trainDir = [Link](t,ds) ∧
guard1 = [Link](seg,[Link](trainDir),con) ∧
guard2 = [Link](guard1,trainDir,con) ∧
res = [Link] res(t,trainDir)
⇒
[Link](res) = getSBCCLineRes(guard1,cs) ∧
[Link](res) = getSBCCLineRes(guard2,cs) ∧
[Link](res) = getSBCCBranchRes(guard2,cs)
)
16.6 Control 145
When a train is on a single line it must have a reservation in both guards with
the appropriate direction + a branch reservation if driving to a point:
value
position sl sbcc res wf : ControlState × [Link] × [Link] → Bool
position sl sbcc res wf(cs,ds,con) ≡
(
∀ t : [Link],
seg : [Link],
sb1,sb2 : [Link],
dir : [Link],
res : [Link] •
dir = [Link](t,ds) ∧
[Link](t,seg,con,ds) ∧
[Link](seg,con) ∧
sb1 = [Link](seg,[Link](dir),con) ∧
sb2 = [Link](seg,dir,con) ∧
res = [Link] res(t,dir) ⇒
[Link](res) = getSBCCLineRes(sb1,cs) ∧
[Link](res) = getSBCCLineRes(sb2,cs) ∧
([Link](sb2,con) = [Link] ⇒
[Link](res) = getSBCCBranchRes(sb2,cs))
)
Position of barriers and status of crossing signals must conform Allowed (bar-
rier,signal) states: (UP,OFF), (UP,ON), (MOVINGDOWN,ON), (DOWN,OFF),
(MOVINGUP,OFF)
value
barrierPos signalStatus Consistent : [Link] × [Link] → Bool
barrierPos signalStatus Consistent(s,con) ≡
(
∀ sb : [Link] •
[Link](sb,con) = [Link] ⇒
case [Link](sb,s,con) of
[Link] → [Link](sb,s,con) ∈ { [Link], [Link] },
[Link] → [Link](sb,s,con) = [Link],
[Link] → [Link](sb,s,con) = [Link],
[Link] → [Link](sb,s,con) = [Link]
end
)
The initial requirement specifies some requirements to how the control state
must look like initially. An axiom is stated to make sure that the requirements
146 Initial Model
are satisfied:
value
initReq : ControlState × [Link] × [Link] → Bool
initReq(cs,ds,con) ≡
is wf(cs,ds,con) ∧
no sbcc res(cs) ∧
sbcc not preparing(cs) ∧
no tcc res(cs) ∧
tcc not requesting(cs) ∧
tcc not decelerating(cs)
axiom
[ initial state ]
initReq(initControlState,[Link],[Link])
Notice that the initial requirement includes that the control state should be
wellformed. The used functions is explained in the following.
no sbcc res
value
no sbcc res : ControlState → Bool
no sbcc res(cs) ≡
(
∀ sb : [Link],
branchRes,lineRes : [Link] •
branchRes = getSBCCBranchRes(sb,cs) ∧
lineRes = getSBCCLineRes(sb,cs)
⇒
{branchRes} ∪ {lineRes} = {[Link]}
)
value
sbcc not preparing : ControlState → Bool
sbcc not preparing(cs) ≡
(
∀ sb : [Link] •
∼isPreparing(sb,cs)
)
16.6 Control 147
no tcc res
value
no tcc res : ControlState → Bool
no tcc res(cs) ≡
(
∀ t : [Link] •
∼hasTCCRes(t,cs)
)
value
tcc not requesting : ControlState → Bool
tcc not requesting(cs) ≡
(
∀ t : [Link] •
∼isTCCRequesting(t,cs)
)
value
tcc not decelerating : ControlState → Bool
tcc not decelerating(cs) ≡
(
∀ t : [Link] •
∼isTrainDecelerating(t,cs)
)
axiom
[ getSBCCLineRes setSBCCLineRes ]
∀ sb1,sb2 : [Link], cs : ControlState, sbRes : [Link],
con : [Link] •
getSBCCLineRes(sb1,setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
if(sb1 = sb2)
then
[Link](sbRes)
else
getSBCCLineRes(sb1,cs)
end
If the observer and generator gets the same SB as argument, the observer returns
the same line reservation as has been input to the generator. This reflects the
intended behaviour, that the generator only changes the line reservation of the
SB it get as argument.
axiom
[ gen wf setSBCCLineRes ]
∀ sb : [Link], res : [Link],
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) ∈ {[Link], [Link]}
⇒
is wf(setSBCCLineRes(sb,[Link](res),cs),ds,con)
Decomposed model
This chapter describes how the model is decomposed into several schemes to
obtain an object oriented structure well suited for OOP1 .
The full decomposed model can be found in appendix F.2 and the method for
decomposition is described in section 15.2.
17.2 Types
The Types module is not decomposed but kept exactly as in the initial model.
17.3 Statics
The Statics module is now decomposed. Four new modules are created as objects
in Statics. The type of interest (Configuration) in Statics is now made as a
product of the four objects’ type of interest. The actual configuration instance
(conf ) is now made up of the four object’s actual configurations:
object
SBs : AA SBs1(T),
ESAs : AA ESAs1(T),
Segs : AA Segs1(T),
Trains : AA Trains1(T)
type
Configuration = [Link] × [Link] × [Link] × [Link]
value
conf : Configuration = ([Link], [Link], [Link], [Link])
All basic and some derived observers are copied to the appropriate modules, so
that each module deals with its own area. Derived observers that use observers
from more than one of the new modules are kept in Statics. The other observers
in Statics are changed so that they just call the equivalent observers in the
appropriate modules.
The wellformedness function (is wf) is changed so that is uses the wellformedness
functions in the four new modules along with the composed wellformedness
predicate, i.e. the wellformedness that deals with more than one of the new
modules:
value
is wf : Configuration → Bool
is wf((sbs,segs,esas,ts)) ≡
[Link] wf(sbs) ∧
[Link] wf(segs) ∧
[Link] wf(esas) ∧
17.3 Statics 151
[Link] wf(ts) ∧
composed is wf((sbs,segs,esas,ts))
17.3.1 SBs
The SBs module only deals with switch boxes. The entire module can be found
in appendix F.2.2.
type
SBs
value
sbsConf : SBs,
17.3.2 Segs
The Segs module only deals with segment. The entire module can be found in
appendix F.2.2.
type
Segs
value
segsConf : Segs
17.3.3 ESAs
The ESAs module only deals with end station areas. The entire module can be
found in appendix F.2.2.
type
ESAs
value
esasConf : ESAs
17.3.4 Trains
The trains module only deals with trains. The entire module can be found in
appendix F.2.2.
152 Decomposed model
type
Trains
value
trainsConf : Trains
17.4 Dynamics
The Dynamics module is now decomposed. Two new modules are created as ob-
jects in Dynamics. The type of interest (State) in Dynamics becomes a product
of the two objects’ type of interest. The initial state (initState) is then made
up of the two object’s initial states:
object
TD : AA TrainDyn1(T,S),
SD : AA SBDyn1(T,S)
type
State = [Link] × [Link]
value
initState : State = ([Link], [Link])
All basic and some derived observers and generator are copied to the appropriate
modules, so that each module deals with its own area. Derived observers and
generators that use observers and generators from more than one of the new
modules are kept in Dynamics. The other observers and generators in Dynamics
are changed so that they just call the equivalent observers and generators in the
appropriate modules.
The wellformedness predicate is changed so that is uses the wellformedness
functions (is wf) in the two new modules:
value
is wf : State × [Link] → Bool
is wf((ts,ss),con) ≡
[Link] wf(ts,con) ∧
[Link] wf(ss,con)
The init req function is changed likewise to use the init req functions in the two
new modules along with the is wf function in Dynamics.
value
init req : State × [Link] → Bool
init req((ts,ss),con) ≡
is wf((ts,ss),con) ∧
[Link] req(ts) ∧
[Link] req(ss,con)
17.5 Control 153
17.4.1 TrainDyn
The TrainDyn module only deals with the state of trains. The entire module
can be found in appendix F.2.3.
type
TrainStates
value
initTrainStates : TrainStates
17.4.2 SBDyn
The SBDyn module only deals with the state of switch boxes. The entire module
can be found in appendix F.2.3.
type
SBStates
value
initSBStates : SBStates
17.5 Control
Control is also decomposed but a bit different than Statics and Dynamics as
described in section 15.2.4.
object
SBCC : AA SBCC1(T,S,D,COM),
TCC : AA TCC1(T,S,D,COM)
type
ControlState = SBCCStates × TCCStates,
SBCCStates = [Link] →
m [Link],
TCCStates = [Link] →
m [Link]
value
initControlState : ControlState
The wellformedness predicate (is w)) has not been changed. It still require the
dynamic state to be wellformed and a control state to exists for every TCC and
SBCC.
154 Decomposed model
17.5.1 TCC
The TCC module deals with the one TCC. The entire module can be found in
appendix F.2.4.
type
TCCState
value
initTCCState : TCCState
17.5.2 SBCC
The SBCC module deals with the one SBCC. The entire module can be found
in appendix F.2.4.
type
SBCCState
value
initSBCCState : SBCCState
17.5.3 ComService
As can be seen in the decomposed model diagram in section 17.1 a new scheme
ComService is added. This is needed to enable the control entities TCC and
SBCC, which are now moved to independent schemes, to communicate with
each other.
The ComService scheme basically consists of a channel and functions to ac-
cess the channel. A comService process in the Control scheme reads from the
channel and relays the messages to the appropriate control entity (see also the
message types in section 16.3.8).
The ComService scheme is showed below:
17.6.1 Types
The only change from AA Types0 to AA Types1 is the name of the module.
Therefore it is obvious that AA Types1 directly implements AA Types0.
17.6.2 Statics
17.6.3 Dynamics
end
axiom
in
class
object
T : AA Types1,
S : AA Statics1 (T)
end
` ` AA Dynamics1 (T,S) AA Dynamics0(T,S)
end
17.6.4 Control
AA Control1
∼
tccProcess : [Link] × [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
∼
checkSpeed : [Link] × [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
∼
checkDeceleration : [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
∼
decelerateTrain : [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
∼
accelerateTrain : [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
∼
clearRes : [Link] × ControlState × [Link] → ControlState,
∼
handleRes : [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
∼
tccRequestRes : [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
∼
sendTCCReq : [Link] × [Link] × [Link] × ControlState → ControlState,
∼
sbccProcess : [Link] × [Link] × ControlState × [Link] × [Link] →
ControlState,
∼
prepareProcess : [Link] × ControlState × [Link] × [Link] →
ControlState,
∼
sensorProcess : [Link] × ControlState × [Link] × [Link] →
ControlState,
∼
dePrepareSeg : [Link] × ControlState × [Link] × [Link] →
ControlState × [Link],
prepareSeg : [Link] × [Link] × ControlState × [Link] ×
∼
[Link] →ControlState × [Link],
∼
makeDeRes : [Link] × ControlState × [Link] × [Link] → ControlState,
∼
sendLBDeResMsg : [Link] × [Link] × ControlState → ControlState,
∼
sendLDeResMsg : [Link] × [Link] × ControlState → ControlState,
∼
sendBDeResMsg : [Link] × [Link] × ControlState → ControlState,
∼
sendLBResMsg : [Link] × [Link] × [Link] × ControlState → ControlState,
∼
sendSBCCMsg : [Link] × [Link] × [Link] × ControlState → ControlState,
∼
sbccMsgProcess : [Link] × ControlState × [Link] × [Link] →
ControlState,
∼
handleSBCCMsg : [Link] × [Link] × ControlState →
ControlState × [Link],
handleTCCMsg : [Link] × [Link] × ControlState × [Link] ×
∼
[Link] →[Link] ×
[Link] × ControlState × [Link],
∼
handleLBReq : [Link] × [Link] × ControlState →
ControlState × [Link],
∼
lineBranchFree : [Link] × ControlState → Bool,
∼
lineFree : [Link] × ControlState → Bool,
∼
handleLBResp : [Link] × [Link] × ControlState →
ControlState × [Link],
∼
handleDeResMsg : [Link] × [Link] × ControlState →
ControlState × [Link],
no sbcc res : ControlState → Bool,
sbcc not preparing : ControlState → Bool,
no tcc res : ControlState → Bool,
tcc not requesting : ControlState → Bool,
tcc not decelerating : ControlState → Bool,
17.6 Implementation relation 159
end
` ` AA Control1 (T,S,D) AA Control0(T,S,D)
end
160 Decomposed model
Chapter 18
Concrete model
When the model is made concrete all data types that preciously were sorts are
made concrete. All unspecified functions are made explicit, but no structural
changes has been made.
All concrete modules in their entire can be found in appendix F.3. In the
following all modules is examined and the types that has become concrete is
shown:
18.1 Types
The primary change in the Types module is that ID is made concrete:
type
ID = Text
A few types have been added as well but they are mentioned here. The entire
module can be found in appendix F.3.1.
18.2 Statics
The types in Statics has not been changed since the decomposition step made
Statics concrete.
18.2.1 SBs
type
SBs = [Link] →
m SBData,
18.2.2 Segs
type
Segs = SegsData × SegPoints,
18.2.3 ESAs
type
ESAs == mk esa(getLowSB : [Link],
getHighSB : [Link],
getLowLength : [Link],
getHighLength : [Link])
18.3 Dynamics 163
The ESAs type holds the two end SBs (Low and High) and the length of the
two ESAs.
18.2.4 Trains
type
Trains = [Link] →
m TData,
18.3 Dynamics
The types in Dynamics has not been changed since the decomposition step made
Dynamics concrete.
18.3.1 TrainDyn
type
TrainStates = [Link] →
m TrainState,
The TrainState type holds the physical state data for one train.
The TrainStates type is a mapping from TrainID to TrainStates. In this way
TrainStates can contain the states for trains. The wellformedness predicate says
i.a. that TrainStates should contain states for all trains.
164 Concrete model
18.3.2 SBDyn
type
SBStates = [Link] →
m SBState,
The SBState type holds the physical state data for one SB.
The SBStates type is a mapping from SBID to SBStates. In this way SBStates
can contain the states for SBs. The wellformedness predicate says i.a. that
SBStates should contain states for all SBs.
18.4 Control
The types in Control has not been changed since the decomposition step made
Control concrete.
18.4.1 TCC
type
TCCState :: hasTCCRes : Bool ↔ setTCCRes
isTCCRequesting : Bool ↔ setTCCRequesting
isTrainDecelerating : Bool ↔ setTrainDecelerating
18.4.2 SBCC
type
SBCCState :: getLineRes : [Link] ↔ setLineRes
getBranchRes : [Link] ↔ setBranchRes
getLastSensorStatus : [Link] ↔ setLastSensorStatus
getMsgs : [Link]∗ ↔ setMsgs
getPrepRes : [Link] ↔ setPrepRes
18.5 Implementation relation 165
18.5.1 Types
18.5.2 Statics
In the step of making the statics module concrete the signatures of the func-
tions have not changed and no functions are deleted. Therefore the concrete
statics module CA Statics0 directly implements the decomposed statics module
AA Statics1.
18.5.3 Dynamics
axiom
in
class
object
T : CA Types0,
S : CA Statics0(T)
end
` ` CA Dynamics0(T,S) AA Dynamics1(T,S)
end
In the step of making the dynamics module concrete the signatures of the func-
tions have not changed and no functions are deleted. Therefore the concrete
dynamics module CA Dynamics0 directly implements the decomposed dynam-
ics module AA Dynamics1.
18.5.4 Control
CA Control0(T,S,D) AA Control1(T,S,D)
end
In the step of making the control module concrete the signatures of the func-
tions have not changed and no functions are deleted. Therefore the concrete
control module CA Control0 directly implements the decomposed control mod-
ule AA Control1.
Chapter 19
Imperative model
When the model is made imperative variables are introduced. The type of
interest is removed as parameter to the functions because the functions now
read and write directly at the variables instead. The signatures are changed to
reflect this.
The following sections describes the variables that are introduced.
19.1 Types
The Types module does not have a type of interest. Therefore it does not need
any variable(s).
19.2 Statics
Statics will not have a variable to hold the configuration since the module is
decomposed. Instead the sub modules of Statics contain the variables that
together form the entire configuration.
No functions write to one of the variables in the sub modules of Statics since the
variables hold a configuration and not a state. Besides no generator functions
exists. Therefore the configuration could be maintained as a constant rather
than a variable, but that would not be suitable for implementing in JAVA since
the simulator should be generic. Without a variable only one configuration
could be used and it should be stated directly in the JAVA code rather than
being loaded at start up.
168 Imperative model
19.2.1 SBs
The SBs module will have one variable containing the type of interest. It is
initialized to the actual configuration value sbsConf
variable
v SBs : SBs := sbsConf
value
sbsConf : SBs
19.2.2 Segs
The Segs module will have two variables. One containing the type of interest and
one containing the brake- and reservation point. The variables are initialized to
the actual configuration values.
variable
v segs : SegsData := segsDataConf,
v points : SegPoints := segPointsConf
value
segsConf : Segs = (segsDataConf,segPointsConf),
segsDataConf : SegsData,
segPointsConf : SegPoints
19.2.3 ESAs
The ESAs module will have one variable containing the type of interest. It is
initialized to the actual configuration value esasConf
variable
v ESAs : ESAs := esasConf
value
esasConf : ESAs
19.2.4 Trains
The Trains module will have one variable containing the type of interest. It is
initialized to the actual configuration value trainsConf
19.3 Dynamics 169
variable
v trains : Trains := trainsConf
value
trainsConf : Trains
19.3 Dynamics
Like in the Statics module, the Dynamics module will not have variables since
it is decomposed.
19.3.1 TrainDyn
The TrainDyn module will have one variable containing the type of interest. It
is initialized to the initial state initTrainStates
variable
v TrainStates : TrainStates := initTrainStates
value
initTrainStates : TrainStates
19.3.2 SBDyn
The SBDyn module will have one variable containing the type of interest. It is
initialized to the initial state initSBStates
variable
v SBStates : SBStates := initSBStates
value
initSBStates : SBStates
19.4 Control
Like in the Statics and Dynamics modules, the Control module will not have
variables since it is decomposed.
A little change in the structure of the Control module has been made. Before
Control contained one SBCC module and one TCC module and then two arrays
containing the states of these. Now two object arrays are made containing all
the TCCs and SBCCs that now contain their own control state as variables.
170 Imperative model
19.4.1 TCC
The TCC module will have three variables that together contain the three parts
of the type of interest. The variables are initialized to the their parts of the
initial TCC control state initTCCState.
type
TCCState :: hasTCCRes : Bool
isTCCRequesting : Bool
isTrainDecelerating : Bool
variable
v tccRes : Bool := hasTCCRes(initTCCState),
v isReq : Bool := isTCCRequesting(initTCCState),
v isDec : Bool := isTrainDecelerating(initTCCState)
value
initTCCState : TCCState
19.4.2 SBCC
The SBCC module will have five variables that together contain the five parts
of the type of interest. The variables are initialized to the their parts of the
initial SBCC control state initSBCCState.
type
SBCCState :: getLineRes : [Link]
getBranchRes : [Link]
getSensorStatus : [Link]
getMsgs : [Link]∗
getPrepRes : [Link]
variable
v lineRes : [Link] := getLineRes(initSBCCState),
v branchRes : [Link] := getBranchRes(initSBCCState),
v sensorStatus : [Link] := getSensorStatus(initSBCCState),
v msgs : [Link]∗ := getMsgs(initSBCCState),
v prepRes : [Link] := getPrepRes(initSBCCState)
value
initSBCCState : SBCCState
This chapter concerns all aspects of implementing the actual simulator in JAVA.
The method of translating RSL to JAVA is presented. An overview of the
structure of the final JAVA code is shown an explained. A few major differences
between the model and the JAVA simulator is discussed.
Although the model has been refined to an imperative model the translation to
JAVA is not trivial. There is no way to verify that the JAVA program is an
implementation of the RSL model. The only way to make this translation is
to convert the model step by step and find appropriate JAVA structures which
correspond to the RSL structures.
Notation: When expressing something about JAVA code in this section it
is shown in typewriter format like int and Vector. When addressing RSL
structures basic types are written in bold face as Int and Bool. Derived types
are emphasized like TrainState.
The semantics of schemes and objects in RSL has not been investigated in this
project. It is assumed that schemes and objects are the same as class expression
and can be directly translated to JAVA classes.
In the specification of the model, top level values and global objects have not
been used with the goal of easing the implementation to JAVA.
172 Implementing the simulator
The basic types in the RSL model such as Nat, Int, Bool and Text have been
directly translated to the JAVA built-in types int, boolean and String. If
the types int and boolean are used in a context where an object is necessary
(ex. stored in a Vector or Hashtable) the corresponding JAVA wrapper classes
Integer and Boolean are used.
One disadvantage of JAVA is the typing model of the basic types. There is no
way to create abbreviation types as in RSL. Therefore if two types are of the
same max type in RSL then they cannot be distinguished in JAVA if directly
translated:
RSL:
type
ID1 = Text,
ID2 = Text
value
id1 : ID1,
id2 : ID2
JAVA:
String id1;
String id2;
As can be seen in the examples above the RSL values id1 and id2 have different
types whereas in JAVA they do not. Therefore the JAVA variables would be
applicable to the exact same set of functions and the typing system would not
catch any unintended mix-up of the two variables.
This could be solved by extending the String class to both a ID1 and ID2 class.
It has been chosen not to use the class approach but stick to the basic types.
Developing the JAVA program step by step from the RSL model should avoid
any function being called with wrong arguments. But as long as the basic types
are used for more than one data type consistency can not be ensured.
Translating the cartesian product (CP) type to JAVA is fairly straight forward.
The CP type is used in RSL for grouping data in a common container. This
can be conveniently translated into a JAVA class with get and set methods for
data access. This is illustrated in the example below:
RSL:
20.1 Translating the model to JAVA 173
Figure 20.1: ID1 and ID2 as two disjoint types extending String
type
Cartesian = Int × Bool
JAVA:
class Cartesian
{
int var1;
boolean var2;
type
A, B,
ABMap = A →
m B
First B should be made a class with internal variables reflecting whatever in-
formation the CP contains (see section 20.1.3). The actual map structure could
be translated to a Hashtable containing the train state objects as value having
the A as keys.
174 Implementing the simulator
One disadvantage using this interpretation is that the JAVA Hashtable does
not have any kind of type checking (before the JAVA version 1.5). This means
that though the idea of the map is only to map A to B, the key and value in
the JAVA Hashtable can be of any type.
In this project this is solved by making a class that contains a JAVA Hashtable
in a variable. The important methods in a JAVA Hashtable are then defined
in this class in terms of the similar functions in the JAVA Hashtable. The
signatures of the functions are changed so the key and value parameters are
only allowed to be the types A and B respectively. This solution is illustrated
in figure 20.2.
A variant type defines a main type which can exist in the form of several sub
types (or can be constructed by different constructors). In this project we have
separated the variant in three different cases:
1. All sub types are constructors with at least one argument. No constants.
2. As above but with one constant expressing the empty type or non-existense
of the main type.
20.1 Translating the model to JAVA 175
1. All constructors:
An example of this case is shown beneath:
RSL:
type
Variant == con1 (dest11 : T11 , dest12 : T12 )
| con2 (dest21 : T21 , dest22 : T22 )
Here the main type Variant is translated to the abstract JAVA class Variant.
Two classes extend this class, namely Con1, Con2. The sub types or constructors
are handled exactly like the cartesian product type. I.e. classes are created
containing variables with same types as the variant constructor arguments. a
JAVA example is shown below:
JAVA:
type
Variant2 == con2 1(dest2 11 : T1 )
| empty
Here the constant empty is the empty value for the Variant type. In JAVA this
can be implemented exactly as case 1 above with the empty constant converted
to a JAVA class with no internal values.
In this project it has been chosen to implement the empty values as null. Again
the disadvantage of this approach is that no type checking is made on the value
null and could therefore be any of the constants using null as value.
176 Implementing the simulator
The latter solution has been chosen, because it would be the intuitive solution
in JAVA and that it is not considered that great an inconsistence. On the other
hand, should a generic solution be required the prior solution with an empty
class should be considered.
3. All constants:
An RSL example is illustrated below:
RSL:
type
Variant == CONST1 | CONST2
Here the type Variant is a pure collection of constants. Again this could be
implemented as classes in the generic case, to ensure type checking, in general
algorithms converting variants.
But this complicates the intuitive use of these constants which would be in a
case structure which corresponds to a switch in JAVA. But if these constants
were implemented as classes a switch structure could not handle these. This
should then be handled with instanceof like example below:
JAVA:
Figure 20.4: Variant class using the class Empty as the empty value
In this project it has been solved by converting all constants to integer constants.
This would look like the example below:
JAVA:
JAVA:
Figure 20.7: Variant class with static integer constants and internal variable
when using this variant as function parameter type checking can be used:
JAVA:
20.1 Translating the model to JAVA 179
Case expressions are mainly used for deciding which constructor is used to create
a variant value.
As seen in section 20.1.5: “Variants” above, we have two different approaches
to choose among which is heavily dependent on the structure of the variant.
If the RSL case expression selects among static integers then a switch in JAVA
can be used, but if the variant constructors has parameters then we saw in
last section that the RSL case expression is now an if-then-else in JAVA
utilizing the instanceof operator which determines if an object is an instance
of a specific class.
20.1.7 Preconditions
value
f : T1 → T2
f(x) ≡ ...
pre precond(x)
public T2 f(T1 x)
{
180 Implementing the simulator
if (!precond())
throw new Exception(‘‘some error msg’’);
...
}
Universal quantification
The universal quantifier (∀) expresses that the predicate following is satisfied
by all possible values of some type. An example is shown below:
RSL:
axiom
∀x: T • p(x)
For this expression to be translated into JAVA, it is crucial that the type T
represents some finite set (Vector, Hashtable or other set types) of values.
This could then be translated to:
20.1 Translating the model to JAVA 181
JAVA:
return true;
Exists quantification
The existential quantifier (∃) expresses that at least one value of some type
satisfies some predicate. An example is shown below:
RSL:
axiom
∃x: T • p(x)
Using an example like the JAVA example above, a structure like the one below
would perform the same function in JAVA:
JAVA:
return false;
If the specific existential quantifier (exists!) is used then a count variable should
be added to the JAVA code above. Only when a certain amount of values
matches the predicate, the entire expression is true. An example is given below:
RSL:
axiom
∃! x1,x2 : T • p(x)
int counter = 2
for (; [Link](); [Link]())
182 Implementing the simulator
{
if (p([Link]()))
counter--;
}
if (counter == 0)
return true;
else
return false;
Implication
The implication (⇒) could easily be translated to its equivalent in RSL before
being translated to JAVA:
RSL:
p(x) ⇒ r(x)
is equivalent to
RSL:
∼p(x) ∨ r(x)
(!p(x) || r(x))
Complex expressions
In expression, more complex than the ones in the section above, many values
can be universally quantified at the same time. Using the technique from the
sections above we should create a for-loop for each quantified value.
But this is not always the best approach. The suggestion above would surely
work but could introduce some unnecessary processing time. An example using
the types of the RSL model in this project is given below:
RSL:
axiom
∀ t : [Link], speed, maxSpeed : [Link] •
speed = [Link](t) ∧
maxSpeed = [Link](t)
⇒
speed ≤ maxSpeed
20.1 Translating the model to JAVA 183
When this RSL expression is implemented in JAVA then the type [Link] is
implemented as a double. Therefore it would be very expensive to loop through
all doubles until one matches the expression [Link](t).
Clearly it is just the intention to extract the properties from the train and
compare them. It would therefore be trivial to create a loop over all trains and
compare their speed to their max speed.
initialise axiom
In the imperative specification of the model an axiom [initial] was added. This
axiom from the SBCC scheme is shown below:
[ initial ]
initialise post initReq()
it requires that the predicate initReq is true after initializing the module. This
implies that all variables are fulfills this predicate. Since all variables are ini-
tialized by the initial state value in each module, this value should fulfill the
initReq predicate.
This has been implemented in JAVA by calling the predicate in the constructor
of a class with a such axiom. An example is shown below:
class StateClass
{
State state;
20.1.9 Concurrency
If the RSL model was of concurrent nature then a lot of other considerations
should be taken into account. But because this RSL model is not concurrent
we have decided to put the ideas for concurrency in appendix E.
184 Implementing the simulator
This section shows how the function getNextSB in the Statics module in the
RSL model is translated to JAVA.
RSL: getNextSB
value
/∗ Given an SB, it returns the next SB ∗/
∼
getNextSB : [Link] × [Link] → read Segs.v segs, SBs.v SBs [Link]
getNextSB(sb,dir) ≡
let
nextSeg = getSBSeg(sb,dir)
in
case nextSeg of
[Link](segID) → getSegSB(segID,dir),
[Link](upSeg,downSeg) → getSegSB(upSeg,dir)
end
end
pre getSBType(sb) 6= [Link] ∨ getEndDir(sb) 6= dir
JAVA: getNextSB
/**
* Given an SB, it returns the next SB
**/
public String getNextSB(String sb,int dir)
throws Exception
{
/* Check precondition */
if(getSBType(sb).isEndSB() && getEndDir(sb) == dir)
throw new Exception("No next SB after the SB (" + sb + ")");
return null;
}
When converting from RSL to JAVA the precondition is tested in the start of
the function. If it is not satisfied the function throws an exception
In RSL nextSeg is created to hold the return value of getSBSeg by using a
let-in-end expression:
RSL:
let
nextSeg = getSBSeg(sb,dir)
in
...
end
In JAVA nextSeg is a variable that likewise holds the return value of getSBSeg.
JAVA:
The RSL code between the in and end keywords in the let-in-end expression is
a case expression:
RSL:
case nextSeg of
[Link](segID) → getSegSB(segID,dir),
[Link](upSeg,downSeg) → getSegSB(upSeg,dir)
end
return getSegSB([Link](),dir);
}
return null;
In JAVA you cannot use the equivalent switch-case expression to the RSL
expression case. Therefore the if expression and the instanceof operator is
used to test the type of the nextSeg variable.
types contains a number of entity classes derived from the data types in the
Types module in the model.
statics contains a number of classes derived from the Statics module in the
model.
dynamics contains a number of classes derived from the Dynamics module in
the model.
20.2 JAVA program structure 187
control contains a number of classes derived from the Control module in the
model.
gui contains a number of classes used to make the graphical user interface (GUI)
of the simulator. The configuration editor is not a part of this package.
editor contains a number of classes used to make the graphical user interface
for the configuration editor part of the simulator.
exceptions contains a number of exception classes used for error handling.
The next sections describe in further details the content of these packages.
The most important classes in the types package are shown in figure 20.9 and
in figure 20.10.
Figure 20.9 shows a number of different classes (mostly entity classes). Some of
them are composite. The classes in figure 20.9 are easy recognized in the Types
module in the model.
Figure 20.10 shows some classes used in the control part for communication
purpose. The ComMsg class is used for sending messages between trains (TCCs)
and SBs (SBCCs). The ComID class contains the ID of either a train or a SB
while the Message class contains the actual message. The structure of the classes
in figure 20.10 is easy recognized in the Types module in the model.
188 Implementing the simulator
The most important classes in the statics package are shown in figure 20.11.
The structure of the classes is easy recognized in the Statics part of the model.
Statics is the main class in the statics package. It gathers everything dealing
with the configuration of the railway line.
Trains contains the configuration part that deals with trains only and functions
to read from this configuration part.
Segs contains the configuration part that deals with segments only and func-
tions to read from this configuration part.
SBs contains the configuration part that deals with SB only and functions to
read from this configuration part.
ESAs contains the configuration part that deals with the two ESAs only and
functions to read from this configuration part.
TrainData is an entity class containing the configuration data for one train.
SegData is an entity class containing the configuration data for one segment.
20.2 JAVA program structure 189
SBData is an entity class containing the configuration data for one SB.
ESAData is an entity class containing the configuration data for both ESAs.
The most important classes in the dynamics package are shown in figure 20.12.
The structure of the classes is easy recognized in the Dynamics part of the
model.
TrainDyn contains the part of the physical state that deals with trains only,
functions updating the position and speed of the trains and functions to
read from the states.
SBDyn contains the part of the physical state that deals with SBs only and
functions to read from the states.
TrainState is an entity class containing the physical state of one train. The
TrainState objects are stored in the TrainStates object.
SBState is an entity class containing the physical state of one SB. The SBState
objects are stored in the SBStates object.
The most important classes in the control package are shown in figure 20.13.
The structure of the classes is easy recognized in the Control part of the model.
Control is the main class in the control package. It gathers everything dealing
with the control state of the railway line. It i.a. contains two objects of
the TCCs and SBCCs class.
20.2 JAVA program structure 191
TCC contains the control state of one train, functions to modify the state,
functions implementing the TCC algorithm and functions to communicate
with other TCCs and SBCCs. The TCC objects are stored in the TCCs object.
SBCC contains the control state of one SB, functions to modify the state,
functions implementing the SB algorithm and functions to communicate
with other SBCCs and TCCs. The SBCC objects are stored in the SBCCs
object.
ComService provides the communication service that enables the entities (TCC
and SBCC) to communicate with each other.
The most important classes in the gui package are shown in figure 20.14.
Simulator is the main class of the simulator. It starts up the GUI etc.
SimulatorListener is an action listener class that handles the events from the
GUI (pressing buttons etc.)
192 Implementing the simulator
the physical system is ticked but before the control system is ticked so
that the control system always can undo the action if it is not allowed (if
it will result in the speed being to large etc.)
Ticker is a timer class used for ticking of the physical system and the control
system. At every tick it also performs the train driver action from the
TrainDriverAction class and updates the RailwayLinePanel.
The most important classes in the editor package are shown in figure 20.15.
EditorListener is an action listener class that handles all the events from the
configuration editor GUI (pressing buttons etc.).
TopLeftPanel is a GUI panel that contains the buttons in the top left corner
(Import, Export, Delete, Load, Is wellformed and New).
194 Implementing the simulator
ConfScrollPane is a GUI scroll pane that contains a list of all the configura-
tions in the configuration editor.
RLConfPanel is a GUI panel that shows a railway line configuration in the
form of buttons for each entity. When a button is pressed the configuration
data of that entity is showed above and can now be updated.
TrainConfPanel is a GUI panel that shows the configuration data of one train
and allows the user to change this data.
ESAConfPanel is a GUI panel that shows the configuration data of one ESA
and allows the user to change this data.
SegmentConfPanel is a GUI panel that shows the configuration data of one
segment and allows the user to change this data.
PSegsConfPanel is a GUI panel that shows the configuration data of two
coherent branch segments and allows the user to change this data.
SBConfPanel is a GUI panel that shows the configuration data of one SB and
allows the user to change this data.
GeneralException is an Exception class that also has a title besides the ex-
ception message.
CollisionException extends the GeneralException class and specializes the
class for handling exceptions thrown when a collision occurs.
20.3 Translating configuration to XML 195
type
Configuration = [Link] × [Link] × [Link] × [Link]
The first line tells that this is an XML file using the ISO-8859-1 encoding which
allows us to use the danish letters æ, ø and å.
The second line defines the root element of the XML file which must be a
Configuration tag. Furhter more it specifies that the Configuration tag must
contain the four tags SBs, Segs, ESAs and Trains, which match the names of
the types of interest in the submodules of the Statics module.
The third line defines that Configuration must have an attribute called name
which contains the name of the configuration. This is not used in the formal
model but only in the configuration editor in the simulator to identify the dif-
ferent configurations.
1 Document Type Definition
196 Implementing the simulator
The next four sections describe the four tags encapsulated by the Configuration
tag.
20.3.1 SBs
The formal specification of the type of interest (SBs) in the module SBs is
defined like:
value
/∗ Type of interest ∗/
SBs = [Link] → m SBData,
The first line says that the SBs tag should contain at least two SBData tags (the
smallest possible configuration contains two end switch boxes). In the model
the SBs type is a mapping from SBID to SBData. In the DTD each SBData
contains the SBID as a parameter and the SBData tags are just listed after each
other in no particular order inside the SBs.
In the model SBData is a product of different static properties of a SB. In the
DTD these are attributes of SBData except for the up- and down SBSegments
20.3 Translating configuration to XML 197
20.3.2 Segs
The formal specification of the type of interest (Segs) in the module Segs is
defined like:
value
/∗ Type of interest ∗/
Segs = SegsData × SegPoints,
The reservation- and brake points stored in SegPoints in the model are now attributes
of the Segs tag which also contains a number of SegData tags.
In the model SegData is a product of different static properties of a segment. In the
DTD these are attributes of SegData.
20.3.3 ESAs
The formal specification of the type of interest (ESAs) in the module ESAs is defined
like:
value
/∗ Type of interest ∗/
198 Implementing the simulator
These four static properties of the ESAs are now attributes of the ESAs tag.
20.3.4 Trains
The formal specification of the type of interest (trains) in the module Trains is defined
like:
value
/∗ Type of interest ∗/
Trains = [Link] → m TData,
In the model the trains type is a mapping from TrainID to TrainData. In the DTD
each TrainData contains the TrainID as a parameter and the TrainData tags are just
listed after each other in no particular order inside the Trains tag.
In the model TrainData is a product of different static properties of a train. In the
DTD these are attributes of TrainData.
20.4 Differences from RSL model 199
This was solved by having trains wait a random amount of ticks between each re-
request, just like a re-transmission protocol in a basic Ethernet network.
This has not been implemented in RSL because we only want to deal with safety and
not liveness properties which are normally much more complex to prove.
200 Implementing the simulator
Chapter 21
ESAs
The green rectangles in both ends of the railway line represents the ESAs. The low
ESA is shown in the left side.
202 Using the simulator
Switch boxes
Switch boxes are shown as white circles. When a train is located on a SB - or more
precisely: on the sensor at a SB - the SB is colored red. When a SB is preparing one
of its segments it is colored orange.
Crossings
Crossings are shown as two vertical lines at the left and right side of the SB. Two
small boxes are placed respectively above and below the SB. These boxes represents
the state of the crossing. If the boxes are red the crossing is open (barriers are up and
signals are off). Green means that the crossing is closed (barriers are down, signals
are off). If the crossing is opening or closing the color of both boxes are orange.
Points
When the railway line branches at a junction the branches are shown with the down
branch above the up branch.
Boxes are used - as at crossing - to show the position of a point. If a box is green the
21.2 Playing train driver 203
point is connected to the branch close to the box and the opposite box is then red. If
both boxes are orange the point is switching from one branch to the other.
Trains
All trains are initially located in the low ESA. The ID of a train is shown just above the
train. A train is red if it does not have a segment reservation, orange if it is currently
asking for a segment reservation and green if it has received a segment reservation.
21.2.2 Buttons
Three rows of buttons are showed below the railway line layout. The buttons in the
first row represents the two ESAs and all the segments. The buttons in the second
row represents all the SBs and the buttons in the third row represents all the trains
(if any). By pressing a button the static, dynamic and control properties of the entity
the button represents are shown below the buttons.
Train buttons
When a train button is selected four buttons are showed in the Dynamic properties
panel. With these it is possible to play the train driver. You can set the acceleration to
either maximum (Accelerate), minimum (Brake) or to zero (No acceleration). Besides
you can reverse the direction of the train if the train is parked (speed is zero) in an
ESA facing away from the railway line. The control system changes the acceleration
of the train if necessary to keep the railway line safe and consistent.
When an ESA button or a segment button is pressed the static and dynamic properties
of the ESA or segment are shown but without the possibility to change any of the
properties.
SB buttons
When a SB button is pressed the static, dynamic and control properties of the SB are
shown. If the SB is a point SB, a button is provided to be able to switch the point. If
the SB is a crossing SB, a button is likewise provided to be able to open or close the
crossing.
21.2.4 Autodrive
The simulator has been implemented with an autodrive behavior. In the File menu
the autodrive behavior can be switched on and off.
Autodrive behavior means to let the trains drive when they can and are allowed to
do so. If a TCC brakes a train because it does not have a segment reservation for the
next segment, it keeps asking for this reservation. When it has received the reservation
the behavior part of the TCC accelerates the train again. When the train is parked
(holding with zero speed) in an ESA the TCC automatically changes the direction of
the train and accelerate it.
Following this algorithm the trains continuously drives up and down the railway line.
To add a new configuration press the New button in the top left corner. The smallest
possible configuration is then shown. Notice that this configuration is not saved.
To add a segment press the Add SB/Segment button. Then both a SB and a segment
are added just to the left of the right most SB (the end SB at the high ESA).
Before adding the SB/segment pair the type of SB should be chosen by using the
combo box just above the Add SB/Segment button. The SB can not be a end SB. If a
point SB is chosen, two SBs are added along with three segments (two branches and
the stem to the right).
To delete a segment press the Delete SB/Segment button. Then both a SB and a
segment are deleted at the same place as they are added. If the deleted SB is a point
SB both of the point SBs are deleted along with both branches and the right stem.
21.3 Creating new configurations 205
A train is deleted by pressing the Delete button that is shown when the train button
is pressed.
It is possible to update the static properties of all the entities in the configuration by
pressing the button which shows the ID of the entity. Then the properties are shown
above along with a button to apply the changes.
206 Using the simulator
Test
This chapter describes the strategy of how this system has been tested. The system
has only been tested on system level because the complexity of the system makes a
structural test too comprehensive.
Statics All predicates which are part of the is wf() predicate is tested individually
by importing a XML file (see section 21.4) with a configuration which is not
wellformed in the way that it targets the predicate to be tested.
An imported configuration can be tested for wellformedness in the configuration
editor by pressing the Is wellformed button after the configuration is imported.
208 Test
An error message should be shown describing the problem found by the well-
formedness check.
Dynamics All predicates which are part of the safe() predicate is tested individually
by obtaining a state (situation) which is restricted by the targeted predicate.
This is only possible of course if the control system is disabled. Else it is not
possible to obtain a unsafe state.
(This is not entirely true because the user has the power to change points and
crossings even as the trains are passing them while the control system is enabled.
This immediately results in an unsafe state.)
An error message should be shown describing the unsafe situation attained.
Control Several scenarios are run while checking that the information stored in the
control entities (SBCC, TCC) corresponds to the algorithm explained in section
11.1.
The average calculation time has been calculated by running a certain amount of ticks
in a loop while timing it. The results can be seen below in the following sections.
Statics
All sub predicates of the is wf() predicate is tested individually by creating non-
wellformed XML configurations and importing these using the configuration editor.
Non-wellformed configurations are created by negating each invariant expression in
the predicates and then creating configurations which satisfy these negated invariants.
The predicates and the associated tests are listed below:
sbsHaveConf() :
1. An SB’s configuration data does not exist in the configuration even though
its ID exists.
2. The reservation point is less than 0.0.
3. The break point is less than 0.0
resPoint wf() :
1. a trains length added to the reservation distance is greater or equal to a
segments length.
2. the brake point is longer than a segment.
esa seg length() : An ESA is shorter or equal to the brake point.
Dynamics
System states which violate the predicate safe() in the Dynamics module are obtained
by running the simulator. These should be followed by an error message from the
system. All images corresponding to the physical events are listed in appendix D.
noCollisions() :
1. A train crashes frontally into another train.
2. A train crashes into the rear of another train driving UP.
3. A train crashes into the rear of another train driving DOWN.
trainPosPossible() : This predicate is not tested. It only states that if two train are
on same segment driving towards each other, they must be facing each other.
pointsSafe() :
1. A train drives from the stem into a point which is shifting.
2. A train drives from a branch to the stem of a point which is not shiftet to
the branch of the train.
crossingsSafe() : A train drives into a crossing in which the barriers are not down.
Control
A number of scenarios should be run to ensure that the control algorithm is followed.
The system should be checked, that the consistent() predicate holds each time the
control state is changed. This happens at the following events:
Reservation point : When a train crosses this point it should request a reservation.
Brake point :
• The train has a reservation and continues.
• The train has not attained a reservation and begins braking.
Sensor :
1. A sensor is left by a train. The appropriate dereservations should be
executed according to the algorithm.
2. A sensor is activated by a train. Nothing should happen.
Adding to these tests we can set the system to apply the consistent() predicate every
some seconds. This is possible because the predicate was translated to JAVA as was
the rest of the model. This increases our trust in the system to stay consistent.
22.3 Test listings 211
Startup cost
The data in the table clearly indicates that some startup cost is added to the tests.
We can see that when the amount of ticks is increased, the average time for calculating
a tick drops. This is probably caused by calculations taking longer time the first time
being executed. But as more calculations are carried out looking very similar, a lot of
calculation time is saved by caching some intermediate results in the CPU cache.
External processes
But we can also see an indication the tick calculation time rises a bit between the two
last runs from 0.4 ms to 0.42 ms. This could easily be caused by JAVA running some
garbage collection or another process in the windows operating system is using system
resources. Therefore even if a tick takes much less time to calculate than the delay
before calculating the next, we cannot guarantee that the system always calculates in
real time, because the operating systems today run a lot of processes which is out of
our control.
If for example JAVA garbage collection decides to run in the middle of a simulation,
we cannot be sure that the simulator is given enough CPU time to complete its cal-
culations.
212 Test
Ticks threshold
At the time of writing this, the simulator is set with a tick value of 0.05s. This means
that the simulator has 50 ms to complete a tick. And with an average calculation time
of 0.4 ms this should be more than enough.
We still have to remember that this is only the test results of the machine which is
described in the beginning of this chapter. Tick calculation time could easily vary with
the amount of RAM and CPU MHz. But seen from this machines point of view, we
could turn up the time update frequency without risking low performance and thereby
get a more fine-grained simulation.
Configuration size
As mentioned in section 22.1 the initial test configuration contained 1 crossing, 4 points
and 6 trains. Lets see how this varies when the number of points and trains is raised.
We will perform these experiments with a fixed number of ticks 106 .
Clearly it is the number of trains which affects the system the most. This was also the
expected result because a train has many processes which has to be updated at every
tick where SBs does nothing until receiving a message or a sensor event.
Chapter 23
Verification
This chapter lays out the strategy of how to be able to prove / verify safety in the
system developed. The actual formal verification has not been done in this report, but
some informal argumentation (validation) is done later in this chapter.
The saf e predicate only expresses the fact, that for a railway line to be safe, events like
train collisions and derailments has not occurred in the current state. This means that
this predicate actually defines when accidents involving trains physically has occurred.
In the mentioned papers (referred to in the beginning of this section) the saf e predicate
is defined much stronger where a safe state is when two trains are not on the same
segment. This is because these models were very abstract concerning train movement
so this was the obvious choice.
What we would like to hold now is the implication
where s is some state and gen is a generator (event) applying some change to the
state. This means that all events applied to a safe state leads to another safe state.
214 Verification
The idea is that this should hold when using the developed safety / control system.
But it is not enough to require a state to be safe. For the control system to work
properly the state must also be consistent to the rules of the control system. This
means that the control system can only function properly if its internal state represents
the actual state of the physical world. This again means that if a train is on a given
segment, some reservation should exist in the control system that reflects the position
of the train so that no other trains are allowed access it.
Therefore if the state of the control system is not consistent with the physical world
and the control algorithm then it could possibly allow two trains to enter the same
segment. Some examples of saf e states which at some time will lead to an unsafe
state is shown in figure 23.1 and 23.2.
Figure 23.2: A safe state but T2 enters the segment even though it is occupied.
As mentioned above this predicate defines the consistent relationship between the
physical state and the state of the control system.
The idea is now that
But again this is not enough. Because all generators cannot be applied at all times.
The generators in the physical module (Dynamics) has preconditions which are derived
from the predicate (saf e) and therefore guards the system from entering an unsafe
and thereby undefined state of the system.
23.1 The idea of provability 215
So this means that if only the physical system is considered we could state that:
namely that IF saf e holds in a state AND the guard for the specific generator also
holds in that state THEN the state obtained by applying the generator is also safe.
∼
setTrainPosition : [Link] × [Link] × State × [Link] → State
setTrainPosition(tID,pos,(ts,ss),con) ≡
([Link](tID,pos,ts,con),ss)
pre ∼trainPositionOccupied(tID,pos,(ts,ss),con) ∧
∼tpDerailed(pos,getTrainDirection(tID,(ts,ss)),(ts,ss),con),
As seen in the example above the preconditions for this function is ∼ trainP ositionOccupied
and ∼ tpDerailed which express that:
216 Verification
• Another train should not be located at the position that this generator is trying
to occupy.
• The position which the generator is trying to apply to the specific train must
not be at a crossing or point which is not safe for a train to pass.
As mentioned the control module does not contain any preconditions to the purpose of
preserving consistent. It is at the moment not possible to construct such preconditions
because no control entity generators exists in the Control main module. Therefore
these could only express properties about their own local state. This is not enough to
ensure consistent.
Again this is out of scope of this project but these considerations have been made, if
it should be relevant at some time to carry out a proof.
As of now 2 things can be done to make a proof possible:
1. Strengthen the consistent predicate, if possible, so the state of the other control
entities can be derived from its own state and the consistent predicate.
2. Create derived generators in the top Control module so that stronger precondi-
tions can be specified to the generators.
The strong properties mentioned above should be derived from the control algorithm.
Some of these strong properties could be invariants of the algorithm that is not yet
included in the consistent predicate. Some examples could be:
and so on....
23.1.4 Wellformedness
In the same way that generators should preserve the consistent and saf e predicates,
it should also be shown that they preserve wellformedness. If the generators does not
preserve wellformedness then the system does not make sense.
The general proof obligation would look like:
In the same way, if a statement expresses that is wf is preserved, it applies for all
modules (Statics, Dynamics and Control ) because they all define a such predicate. If
the statement is about saf e it concerns only the generators in Dynamics and in the
case of consistent it concerns the generators in the Control module.
where s is some state in the Dynamics module and gen is a generator in this module.
This requires all generators in the Dynamics module to preserve the saf e invariant.
where s is some state in the Control module and gen is a generator in this module.
This requires all generators in the Control module to preserve the consistent invariant.
initReq(s) ⇒ consistent(s)
23.3 Proof: [init is safe] 219
∼
init req : State × [Link] → Bool
init req(s,con) ≡
is wf(s,con) ∧
allTrainsInESA(s) ∧
allTrainsFacingLine(s) ∧
allTrainsStopped(s) ∧
allBarriersUp(con,s) ∧
allPointsNotShifting(con,s),
• crossingsSaf e
1. is true when ∀ t : [Link] • ∼ trainOnSensor(t).
2. trainOnSensor is false when a train is not at two different segments at
once.
3. following the predicate allT rainsInESA we know that all trains are in the
ESAs and therefore cannot be at two segments.
Hereby we have proved informally that the requirements to an initial state also satisfies
the saf e predicate.
Chapter 24
This chapter describes ideas to how the model and simulator could be extended or
changed with different functionality.
it branches into two tracks. In this way complex railway networks could be created.
An example of this is shown in figure 24.1
In such a complex network it would a bit more difficult to guarantee that deadlock
does not occur. Route plans might play a greater role in that kind of railway networks.
Related work
to generate a control system specific to the structure expressed by the XML construct.
In this way one can easily construct new control systems without having to validate
for safety every time. It is only relevant to validate the generic control system.
Thereby it was enough to prove that a satisfied guard implied a consistent state. It
was known that a function would never be executed without the guard being satisfied.
But further validation is needed to ensure safety in this system (see section 23.1.6).
Chapter 26
Discussion
26.1.1 Predicates
The three main modules in the model: Statics, Dynamics and Control all contain a
predicate that checks if the module is wellformed.
For Statics to be wellformed the configuration must be wellformed. Checking this
before the simulation of the railway line is started is very useful, since a lot of errors
may occur at run time, if the configuration is not wellformed. A lot of time might be
spent on searching for errors in the code even though the error is in the configuration
that has been loaded. Rejecting configurations that are not wellformed saves us from
this work.
when using the RAISE development method such predicates are normally specified
on a very early state of development. This forces the developers to agree on what
defines a wellformed system, and how it should work, at the very beginning of the
development phase. If this discussion were to take place deep into the development
phase, discovery of error could possibly prove fatal for the project in form of re-
designing and development costs.
26.1.2 Preconditions
Many of the generators in the model have a precondition that is used to make sure
that the system state stays wellformed, safe and consistent. In the JAVA code these
preconditions are checked in the beginning of each function call. If they are not satisfied
230 Discussion
an exception is thrown.
None of the preconditions should be violated when the control system is turned on.
They are, however, stated anyway. If the control system is turned off, a precondition
might be violated, e.g. if a train passes a crossing that is not closed. In that kind
of situations we get response from the simulator telling what have happened. This is
very useful, since we know when the state has become unsafe.
Some functions have preconditions specifying what proper input is. If these precondi-
tions are violated, the program code might contain an error. I.e. the implementation
of the simulator is not correct. In these situations the preconditions help us finding
these errors. It proved very helpful when debugging the system. It greatly increases
the trust in the software, if the system is run without any preconditions being violated.
pass to enter the new segment is a crossing SB, preparing the segment means to close
the crossing. The reservation is not given before the crossing is closed. If the SB fails
to prepare the segment - e.g. if the barriers do not work properly - a reservation is
not given. A state chart describing the different states of a crossing can be found in
section 9.4.
If the train does not have a reservation to enter the next segment the TCC brakes the
train in a safe distance. Therefore the barriers will be down when the train passes
through the crossing. A road vehicle and a train will therefore only be able to collide at
a crossing if the road vehicle violates the traffic rules by driving through the barriers
(or around them if they do not cover the whole road). The control system cannot
control this kind of situations and it is assumed that they will not happen.
In the simulator it is possible to open and close a crossing manually - also after the
segment is prepared. Using this possibility might violate the safety of the railway
line. Therefore this possibility must not be used when the control system is on, if the
railway line must be safe.
Assuming that manually opening of a crossing does not occur, collisions at a crossing
cannot take place.
These events cannot be avoided by the control system. Therefore it is assumed that
they do not occur, so that the safety of the railway line is not violated.
232 Discussion
Chapter 27
Conclusion
In this chapter we summarize the results of this project and evaluate each part of the
project and associated development phases.
The control system was designed so that only the most necessary processing was done
in the train control computer (TCC). Therefore only a YES or NO was sent from a
switch box (SB) in response to a TCC reservation request. The reason for this was, that
if different kind of trains where to utilize this control system, then the complexity of
the equipment to be installed on each train should be minimal. Almost all complexity
and control decisions are handled in the SBs.
The data type of a Configuration was transformed into a XML DTD (syntax definition
file). This DTD can express all configurations allowed in the considered domain.
Though some wellformedness requirements are directly implemented in the DTD, many
of the wellformedness invariants are enforced by the JAVA configuration editor. The
editor is able to do this through the predicates from the RSL model which are imple-
mented in JAVA functions.
This means that a XML file can express a configuration which is not wellformed even
if obeying the rules of the DTD.
The RSL model was translated into JAVA by using a method also developed in this
thesis (section 20.1). All predicates where translated to JAVA functions and the
essence of the initial axioms were also implemented.
A graphical user interface (GUI) was constructed to visualize the state of the model.
The functionality to manipulate trains, points and crossings where also implemented.
The simulator was constructed so it generically could take a configuration XML file
as input and simulate a control system on the given configuration.
The top level framework to tick the model (see section 5.3), which was not specified
in the RSL model, was also developed.
The design of the GUI was specified and prototyped as diagrams before the actual
implementation took place. The GUI requirements was based on the functionality of
the model.
where sbrk is the braking distance for a train in max speed and saf ety is a safety
distance that the train should never cross when beginning to brake at the brake point.
27.2.3 Model
The development of the model progressed without too many problems. A challenge was
to create a structure which was finely balanced between redundancy and calculation
complexity. By this is meant that there are two approaches when developing such a
model:
27.2.4 Verification
Safety was not verified formally in this thesis but the model has been constructed with
a formal proof in mind. The theory and method of a such proof is described in chapter
23.
The mentioned chapter does not take into account that timing is an issue when ver-
ifying the system, but of course this is of great concern. The possibility of the proof
getting too complex when including timing considerations is to be considered. When
carrying out such a proof one should abstract from the time considerations.
Instead it is encouraged that an abstract model is developed where only the changes in
control state are considered (i.e. trains entering and leaving segments, and reservations
added and removed.). It should be shown that a negative reservation sent to a train
implies that the train stops before it exceeds the segment border. Then this can be
left out of the proof.
Though the model structure is prepared for such a proof, many preconditions and
changes to predicates are probably necessary as pointed out in section 23.1.3. Since a
proof has not been performed, we have no way of knowing whether the current set of
preconditions and predicates are correct and sufficient to carry out such a proof.
Many of the proof obligation in section 23.2 are not stated in the model and therefore
a great deal of axioms and preconditions are still to be defined in the model.
Before an actual proof of safety can be performed, it should also be shown / proved
that generators preserve consistency (wellformedness). Else the system would not
make sense.
This chapter describes the tools that have been used in this project. This includes
tools for writing the report, developing the model, developing the simulator etc.
TeXnicCenter / Latex This report has been written by using Latex in TeXnic-
Center, which is a dedicated Latex editor with functionality to handle projects,
shortcuts to Latex commandoes, etc.
CVS1 has been used to be able to work concurrently with version control.
UltraEdit is a plain editor that has been used to develop the model and to view .txt
files.
DIA is a diagram creation program (UML diagrams etc.). It has been used to draw
different diagrams, the railway line layout, the simulator layout etc.
XDE is a professional tool for drawing UML diagrams that is based on the Eclipse
tool. It has been used to draw state charts when making the algorithms of the
control system and to generate class diagrams from the JAVA code.
Eclipse is a programming IDE that has been used for implementing the simulator in
JAVA.
JAVA is the language the simulator is implemented in. The simulator is implemented
and tested in both version 1.4.2 and 1.5.0
Adope Photoshop has been used to draw and manipulate images.
240 Tools used in this project
Chapter 29
Bibliography
242 Bibliography
Bibliography
Design of GUI
A.1 TrainSimulator
246 Design of GUI
Figure A.1:
Figure A.2:
248 Design of GUI
Appendix B
This section describes the method used and steps taken developing the RSL model.
The description of the method is not specific in references to the actual model but
describe the development method in a more general manner. To read this section the
reader should know of formal development and RSL to some degree.
While developing this model we have tried to follow the RAISE Development Method
from [3] as closely as possible.
The following development steps were carried out:
Introduce types:
• The main type of interest i added as a sort1 . This type is usually some
global state of the considered system or module scope.
• Several other types can be introduced which often represents some entities
or entity related information in the system. These smaller types can be
declared as sorts but can also be respresented by a concrete data type such
as Text or Int.
type
T,
T1 ,
T2 ,
T3 = Text
1 An abstract type declaration in RSL without any concrete data structure or type.
250 RSL method description
Introduce functions:
• Functions which represent the functionality (the possible changes to the
system) are added. As the bodies of these functions are created the need
for lower level functions which directly handles the main type of interest
is discovered.
• Basic functions which extracts (observes) information from the main data
type are called observers.
• Basic functions which generates values of the main type and thereby changes
the system state are called generators.
• At this abstract level it is not yet possible to define bodies for the basic
observer and generator functions. Therefore these are left as signatures.
• Classify the functions as observers, generators and derived and sort them
appropriately.
value
obs1 : T × .. → T1 × ..,
obs2 : T × .. → T2 × ..,
gen1 : T × T1 × .. → T,
gen2 : T × T2 × .. → T
Signature formulation:
• Decide whether functions are total or partial.
• If partial decide on the necessary preconditions for the generators.
• Partial functions can be made total by changing the return type to indicate
success or failure when executing the function. In this way the function
can return failure for all un-wished input.
Formulate observational axioms:
• Formulate observational axioms defining the relationship between all observer-
generator pairs in each module. If the generator has any precondition this
should be specified here. These axioms have the following form:
axiom
[ obs gen ]
∀ t : T, a1 : T1 , .. , an : Tn •
obsi (genj (a1 ,..,an ,t)) ≡ val exp
pre genj guard(a1 ,..,an ,t)
where T is the type of interest, ai are some arguments for the generator
and val exp is some value expression. genj guard is the generator guard
predicate which must be true to be applied.
Add invariants: invariants are formulated as functions and a is wf () function which
is a conjunction of all invariants is added:
value
inv1 : T → Bool,
..
invn : T → Bool,
B.2 Type decomposition (optional) 251
is wf T : T → Bool
is wf T(t) ≡
inv1 (t) ∧ .. ∧ invn (t)
• An axiom for each generator is added stating that the generator preserves
the invariant:
axiom
[ genj wf preserve ]
∀t: T•
genj guard(t,...) ∧ is wf(t) ⇒ is wf(genj (t,...))
axiom
[ init wf ]
is wf(init T) ∧ init reqs(init T)
Hide internal properties: Hide all properties (functions etc.) in the modules which
are not for external use.
Introduce variables:
• Variables for the types of interest are introduced.
• If the type of interest is a product of several types then variables for these
minor types are introduced (in their seperate modules).
• If the minor types exist in seperate modules then objects for each module
is introduced in the utilizing module.
Transform signatures:
• All functions with type of interest as parameter replaces this with Unit
and read any in its signature.
• If a type of interest occur in the result type, it is replaced by a Unit and
a write any (or the specific variable name(s) instead of any).
Transform function bodies: the return value expression in the bodies of the gen-
erators are replaced by an assignment to the appropriate variable. All references
to the type of interest formal parameter is replaced with the variable name.
B.4 Concrete imperative 253
Introduce loops: Recursive function definitions are replaced by loops which is the
imperative counterpart.
Initial value: The initial (constant) value is used to initialize the variable of the same
type:
type
T
value
init T : T
variable
T var : T := init T
254 RSL method description
Appendix C
XML DTD
Test images
This section lists the images illustrating the test scenarios of the Dynamics module.
D.1 Collisions
D.2 Derailings
258 Test images
Concurrency
This section covers the ideas for using concurrency in the RSL model and to translate
this into JAVA.
scheme Semaphore =
class
type
SemReq == TOKEN
channel
semChan : SemReq
value
semProcess : Unit → in semChan out semChan Unit
semProcess() ≡
while (true) do
semChan!TOKEN;
let
token = semChan?
in
()
end
end,
end
The scheme Semaphore is based on the semaphore concept which is well known in
the world of parallel programming - e.g. programming involving several processes or
threads with common data access. The basic idea is that only one process or thread
has write access to a variable at a time. This is ensured by having a token for such a
shared variable. A process that requires access to this variable needs to have its token
first.
The functions below has been created for easy access to token:
As can be seen in the scheme above the token is requested / returned through the get
and put method. Token access is provided through a channel so access to the token is
E.4 Shared variables in JAVA 263
synchronized. The data accessing functions uses the token as shown below:
object
tStateSem : Semaphore
variable
v trainStates : TrainStates
axiom
setTrainState(tid,ts) ≡
[Link]();
v trainStates := v trainStates !! [tid 7→ ts];
[Link](),
All other functions which also requires variable access will then have to use the syn-
chronized functions which accesses the appropriate token.
When several threads request the token at a time the token is sometimes passed directly
from the utilizing thread to the next. The semaphore process itself is necessary to
initially store the token and to store the token when not in use.
Thus keeping the semaphore concept from the RSL model and only synchronizing the
exact same code as between the get() and put() statements in the RSL synchronized
sections.
An easier approach has been used in this project as the whole function is synchronized
if just one section of the function is critical. It will look like this:
{
...
< some critical section >
...
}
1. Shared variables
2. Socket (TCP / IP) communication
3. Direct function calls
For type dependent channels the above solution needs to be extended with synchro-
nized functions read() / write() which typecasts the return / input values for the
functions above to the appropriate type.
In fact the MethodThreadRunner class can also be used in the sense of parallel execu-
tion. Take for example the RSL expression func1() k func2() . This could easily be
translated to JAVA. It would look like the below:
[Link](); [Link]();
[Link](); [Link]();
266 Concurrency
This piece of code terminates when both func1() and func2() has terminated.
Appendix F
RSL modules
F.1.1 Types
scheme AA Types0 =
class
type
/∗ Entity ID types ∗/
ID,
ESAID = End,
SBID = {| sb : ID • sbIDLimit(sb) |},
SegmentID = {| seg : ID • segIDLimit(seg) |},
TrainID = {| t : ID • trainIDLimit(t) |},
/∗ Physical parameters ∗/
Length = Real,
Speed = Real,
Acceleration = Real,
/∗ Neighbour of a SB in a direction ∗/
SBSegment == seg(getSeg : SegmentID) |
point(getUpSeg : SegmentID,
getDownSeg : SegmentID) |
esa(getESA : ESAID),
/∗ The type of a SB ∗/
SBType == POINTSB | ENDSB | CROSSINGSB | PLAINSB,
/∗ The segments etc around a point ∗/
268 RSL modules
/∗ Location/position of a train ∗/
TrainPosition :: frontPos : SegmentPosition ↔ setFrontPos
rearPos : SegmentPosition ↔ setRearPos,
Tick = Real,
/∗ From control ∗/
HasRes == res(Reservation) | noRes,
HasSeg == isSeg(SegmentID) | noSeg,
value
/∗ The tick interval in seconds ∗/
tick interval : Tick,
inverseDir(dir) ≡
case dir of
UP → DOWN,
DOWN → UP
end,
end,
/∗ Determines if a TrainPosition is
located on one segment ∗/
trainOnlyOnESA : TrainPosition → Bool
trainOnlyOnESA(pos) ≡
case getLoc(frontPos(pos)) of
isESA( ) →
(
case getLoc(rearPos(pos)) of
isESA( ) → true,
→ false
end
),
→ false
end,
end
F.1.2 Statics
context: AA Types0
scheme AA Statics0(T : AA Types0) =
class
type
/∗ Main railway line configuration type ∗/
Configuration
F.1 Initial model 271
value
conf : Configuration,
/∗ Basic Observers ∗/
/∗ ESA observers ∗/
∼
getESASB : [Link] × Configuration → [Link],
∼
getESALength : [Link] × Configuration → [Link],
esaExistsInConf : [Link] × Configuration → Bool,
/∗ SB observers ∗/
∼
getSBSeg : [Link] × [Link] × Configuration →
[Link],
∼
getSBType : [Link] × Configuration → [Link],
sbExistsInConf : [Link] × Configuration → Bool,
/∗ Segment observers ∗/
getSegSB : [Link] × [Link] ×
∼
Configuration → [Link],
∼
getSegLength : [Link] × Configuration → [Link],
∼
getSegMaxSpeed : [Link] × Configuration → [Link],
segExistsInConf : [Link] × Configuration → Bool,
/∗ Train observers ∗/
∼
getTrainLength : [Link] × Configuration → [Link],
∼
getTrainMaxSpeed : [Link] × Configuration → [Link],
∼
getTrainMaxAcc : [Link] × Configuration → [Link],
∼
getTrainMaxDec : [Link] × Configuration → [Link],
trainExistsInConf : [Link] × Configuration → Bool,
/∗ Auxiliary functions ∗/
/∗ Determines if a SB is a PointSB ∗/
∼
isPointSB : [Link] × Configuration → Bool
isPointSB(sb,con) ≡
getSBType(sb,con) = [Link],
∼
getOppositeGuard : [Link] × Configuration → [Link]
getOppositeGuard(sb,con) ≡
let
sbType = getSBType(sb,con),
dir = if(sbType = [Link]) then getPointDir(sb,con)
else getEndDir(sb,con) end,
lineDir = [Link](dir)
in
getSingleLineGuard(getNextSB(sb,lineDir,con),lineDir,con)
end
pre isLineGuard(sb,con),
getSingleLineGuards(seg,con) ≡
let
sb = getSegSB(seg,[Link],con)
in
{ getSingleLineGuard(sb,[Link],con),
getSingleLineGuard(sb,[Link],con) }
end
pre ∼segIsBranch(seg,con),
/∗ Invariants ∗/
is wf : Configuration → Bool
is wf(con) ≡
sbs is wf(con) ∧
segs is wf(con) ∧
esas is wf(con) ∧
trains is wf(con) ∧
composed is wf(con),
sbs is wf(con) ≡
sbsHaveConf(con) ∧
getSBSeg diff(con) ∧
getSBSeg point wf(con) ∧
getSBSeg injective(con) ∧
getSBSegType wf(con),
/∗∗
∗ The SB in the end of a segment is different
∗ for two different segments or they are the
∗ same in both direction (being branches)
*∗/
getSegSB injective : Configuration → Bool
getSegSB injective(con) ≡
(
∀ seg1, seg2 : [Link],
dir : [Link] •
seg1 6= seg2 ⇒
(
getSegSB(seg1,dir,con) 6= getSegSB(seg2,dir,con)
)
∨
(
getSegSB(seg1,[Link],con) = getSegSB(seg2,[Link],con) ∧
getSegSB(seg1,[Link],con) = getSegSB(seg2,[Link],con)
)
),
brakeResPoint wf(con) ≡
getResPoint(con) > getBrakePoint(con),
sb2 = getNextSB(sb,dir1,con),
pSegs2 = getSBPointSegs(sb2,con)
in
[Link](pSegs1) = [Link](pSegs2) ∧
[Link](pSegs1) = [Link](pSegs2)
end
),
F.1 Initial model 279
⇒
brakeP > brakeL + s err
),
axiom
[ is wf ]
is wf(conf)
end
F.1.3 Dynamics
context: AA Statics0
scheme AA Dynamics0(T : AA Types0,S : AA Statics0(T)) =
class
type
/∗ Type of interest ∗/
State
value
initState : State,
F.1 Initial model 281
/∗ Point observer ∗/
∼
getPointPosition : [Link] × State × [Link] → [Link],
∼
getPointTicks : [Link] × State × [Link] → [Link],
/∗ Point generator ∗/
setPointPosition : [Link] × [Link] × State ×
∼
[Link] → State,
∼
setPointTicks : [Link] × [Link] × State × [Link] → State,
/∗ Crossing observer ∗/
∼
getBarrierPosition : [Link] × State × [Link] → [Link],
∼
getSignalStatus : [Link] × State × [Link] → [Link],
/∗ Crossing generator ∗/
setBarrierPosition : [Link] × [Link] × State ×
∼
[Link] → State,
∼
setSignalStatus : [Link] × [Link] × State × [Link] → State,
/∗ Sensor observer ∗/
getSensorStatus : [Link] × State → [Link],
/∗ Sensor generator ∗/
∼
setSensorStatus : [Link] × [Link] × State × [Link] → State,
/∗ Train observer ∗/
getTrainAcc : [Link] × State → [Link],
getTrainSpeed : [Link] × State → [Link],
getTrainPosition : [Link] × State → [Link],
getTrainDirection : [Link] × State → [Link],
/∗ Train generator ∗/
∼
setTrainAcc : [Link] × [Link] × State × [Link] → State,
∼
setTrainSpeed : [Link] × [Link] × State × [Link] → State,
setTrainPosition : [Link] × [Link] × State ×
∼
[Link] → State,
∼
setTrainDirection : [Link] × [Link] × State → State,
front = [Link](tp),
rear = [Link](tp),
tp = [Link] TrainPosition(rear,front),
s = setTrainDirection(t,dir,s)
in
setTrainPosition(t,tp,s,con)
end,
/∗ Processes ∗/
282 RSL modules
∼
tick : [Link] × [Link] × State → State
tick(tick,con,s) ≡
let
s = tickPoints(tick,con,s),
s = tickCrossings(tick,con,s),
s = tickTrains(tick,con,s)
in
s
end,
∼
tickPoints : [Link] × [Link] × State → State
tickPoints(tick,con,s) ≡
let
points = { p | p : [Link] • [Link](p,con) = [Link] }
in
pointProcess(points,tick,con,s)
end,
∼
pointProcess : [Link]-set × [Link] × [Link] × State → State
pointProcess(points,tick,con,s) ≡
if(points = {})
then
s
else
let
p : [Link] • p ∈ points,
points = points \ {p},
s = updatePoint(p,tick,con,s)
in
pointProcess(points,tick,con,s)
end
end
pre [Link](points,con),
∼
updatePoint : [Link] × [Link] × [Link] × State → State
updatePoint(p,tick,con,s) ≡
let
pp = getPointPosition(p,s,con)
in
case pp of
[Link] → s de setPointPosition(p,[Link],s,con),
[Link] → s de setPointPosition(p,[Link],s,con),
→s
end
end
pre [Link](p,con) = [Link],
∼
tickCrossings : [Link] × [Link] × State → State
tickCrossings(tick,con,s) ≡
let
crossings = { c | c : [Link] • [Link](c,con) = [Link] }
in
crossingProcess(crossings,tick,con,s)
end,
∼
crossingProcess : [Link]-set × [Link] × [Link] × State → State
F.1 Initial model 283
crossingProcess(crossings,tick,con,s) ≡
if(crossings = {})
then
s
else
let
c : [Link] • c ∈ crossings,
crossings = crossings \ {c},
s = updateCrossing(c,tick,con,s)
in
crossingProcess(crossings,tick,con,s)
end
end
pre [Link](crossings,con),
∼
updateCrossing : [Link] × [Link] × [Link] × State → State
updateCrossing(cr,tick,con,s) ≡
let
bp = getBarrierPosition(cr,s,con),
ss = getSignalStatus(cr,s,con)
in
case bp of
[Link] →
(
if(ss = [Link])
then
s de
setBarrierPosition(cr,[Link],s,con)
else
s
end
),
[Link] →
(
s de
(
let
bp = setBarrierPosition(cr,[Link],s,con)
in
setSignalStatus(cr,[Link],s,con)
end
)
),
[Link] → s,
[Link] → s de setBarrierPosition(cr,[Link],s,con)
end
end
pre [Link](cr,con) = [Link],
∼
tickTrains : [Link] × [Link] × State → State
tickTrains(tick,con,s) ≡
let
trains = { t | t : [Link]}
in
trainProcess(trains,tick,con,s)
end,
284 RSL modules
∼
trainProcess : [Link]-set × [Link] × [Link] × State → State
trainProcess(trains,tick,con,s) ≡
if(trains = {})
then
s
else
let
t : [Link] • t ∈ trains,
trains = trains \ {t},
s = updateTrain(t,tick,con,s)
in
trainProcess(trains,tick,con,s)
end
end,
∼
updateTrain : [Link] × [Link] × [Link] × State → State,
/∗ Auxiliary functions ∗/
[Link] →
(
getBarrierPosition(sb,s,con) = [Link]
),
F.1 Initial model 285
→ false
end
end
else
false
end,
∼
getESATrains : [Link] × State → [Link]-set
getESATrains(esa,s) ≡
{ t | t : [Link] • [Link](getTrainPosition(t,s)) },
/∗ If train drives UP then rear pos must be lower than front pos
and vice versa ∗/
train pos dir ok : [Link] × [Link] × State ×
[Link] → Bool
train pos dir ok(dir,tp,s,con) ≡
(
case dir of
[Link] →
(
[Link]([Link](tp),[Link](tp),con)
),
[Link] →
(
[Link]([Link](tp),[Link](tp),con)
)
end
),
∼
getTrainSegments : [Link] × State → [Link]-set
getTrainSegments(t,s) ≡
[Link](getTrainPosition(t,s)),
∼
getTrainBranch : [Link] × State × [Link] → [Link]
getTrainBranch(t,s,con) ≡
(
let
seg : [Link] • seg ∈ getTrainSegments(t,s) ∧
[Link](seg,con)
in
seg
end
)
286 RSL modules
∼
trainFrontInESA : [Link] × State → Bool
trainFrontInESA(t,s) ≡
let
tPos = getTrainPosition(t,s)
in
[Link]([Link](tPos))
end,
)
else
false
end
end,
∼
pointConnected : [Link] × [Link] × State × [Link] → Bool
pointConnected(sbID,seg,ds,con) ≡
let
pointSegs = [Link](sbID,con)
in
case getPointPosition(sbID,ds,con) of
[Link] → (seg = [Link](pointSegs)),
[Link] → (seg = [Link](pointSegs)),
→ false
end
end
pre [Link](sbID,con) = [Link],
∼
trainFrontLoc : [Link] × State → [Link]
trainFrontLoc(t,ds) ≡
case [Link](getTrainPosition(t,ds)) of
[Link]( ) → [Link](getTrainPosition(t,ds)),
[Link](seg) → [Link](seg)
end,
∼
sensor guard : [Link] × [Link] × [Link] × State → Bool
sensor guard(sen,ss,con,s) ≡
(ss = [Link] ∧ trainOnSensor(sen,con,s)) ∨
(ss = [Link] ∧ ∼trainOnSensor(sen,con,s)),
∼
decelerateTrain : [Link] × [Link] × State → State
decelerateTrain(t,con,s) ≡
if(getTrainSpeed(t,s) 6= 0.0)
then
let
maxDec = [Link](t,con),
curDec = getTrainAcc(t,s)
in
if(maxDec 6= curDec)
then
setTrainAcc(t,maxDec,s,con)
else
s
end
end
else
setTrainAcc(t,0.0,s,con)
end,
∼
accelerateTrain : [Link] × [Link] × State → State
accelerateTrain(tID,con,s) ≡
setTrainAcc(tID,[Link](tID,con),s,con),
∼
commonSegs : [Link] × [Link] × State → [Link]-set
commonSegs(tp1,t2,ds) ≡
F.1 Initial model 289
[Link](tp1) ∩ getTrainSegments(t2,ds),
∼
commonSegs : [Link] × [Link] × State → [Link]-set
commonSegs(t1,t2,ds) ≡
getTrainSegments(t1,ds) ∩ getTrainSegments(t2,ds),
case dir1 of
[Link] →
(
if (dir1 = dir2)
then
[Link]([Link](tp1),[Link](tp2),con) ⇒
∼[Link]([Link](tp1),[Link](tp2),con)
else
∼[Link]([Link](tp1),[Link](tp2),con)
end
),
[Link] →
(
if (dir1 = dir2) then
∼[Link]([Link](tp1),[Link](tp2),con) ⇒
[Link]([Link](tp1),[Link](tp2),con)
else
[Link]([Link](tp1),[Link](tp2),con)
end
)
end
),
/∗ Invariants etc. ∗/
290 RSL modules
/∗∗
∗ The position of a train may not overlap
∗ with the position of other trains
*∗/
∼
noCollisions : [Link] × State → Bool
noCollisions(con,s) ≡
(
∀ t : [Link] •
∼trainPositionOccupied(t,getTrainPosition(t,s),s,con)
),
/∗∗
∗ Trains cannot end up on same segment
∗ driving in opposite directions away from each other.
∗
∗ If two train are on same segment driving in opposite
∗ directions then the train driving up must be lower
∗ on the line than the train driving down.
*∗/
∼
trainPosPossible : [Link] × State → Bool
trainPosPossible(con,ds) ≡
(
∀ t1,t2 : [Link], segs : [Link]-set,
tp1,tp2 : [Link], seg : [Link] •
commonSegs(t1,t2,ds) 6= {} ∧
(tp1,tp2) = (getTrainPosition(t1,ds),getTrainPosition(t1,ds)) ∧
getTrainDirection(t1,ds) 6= getTrainDirection(t2,ds) ∧
getTrainDirection(t1,ds) = [Link]
⇒
[Link]([Link](tp1),[Link](tp2),con)
),
/∗∗
∗ If the train is located upon a junction,
∗ the point must be connected to the
∗ branch, on which the train is located
*∗/
∼
pointsSafe : [Link] × State → Bool
pointsSafe(con,ds) ≡
(
∀ sb : [Link], t : [Link], seg : [Link] •
trainOnJunction(t,sb,con,ds) ∧
trainOnSegment(t,seg,con,ds) ∧
[Link](seg,con) ⇒
pointConnected(sb,seg,ds,con)
),
/∗ Wellformedness ∗/
is wf : State × [Link] → Bool
is wf(s,con) ≡
allStatesExists(con,s),
),
[Link](sb,con) = [Link] ⇒
getPointPosition(sb,s,con) ∈ { [Link], [Link] }
)
axiom
[ wellformedness ]
init req(initState,[Link]),
/∗∗
∗ Observer generator axioms
*∗/
/∗ getPointPosition gen ∗/
[ getPointPosition setPointPosition ]
∀ sb1,sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getPointPosition(sb1,setPointPosition(sb2,pp,s,con),con) ≡
if(sb1 = sb2)
then
pp
else
getPointPosition(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getPointPosition setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getPointPosition(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getPointPosition setBarrierPosition ]
∀ sb1,sb2 : [Link], bp : [Link],
s : State,
con : [Link] •
getPointPosition(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getPointPosition setSignalStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
294 RSL modules
getPointPosition(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getPointPosition setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getPointPosition(sb1,setSensorStatus(sb2,ss,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
sensor guard(sb2,ss,con,s) ∧
pointStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
[ getPointPosition setTrainAcc ]
∀ sb1 : [Link], t : [Link], acc : [Link],
s : State,
con : [Link] •
getPointPosition(sb1,setTrainAcc(t,acc,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
acc ≤ [Link](t,con) ∧
[Link](t,con) ≤ acc,
[ getPointPosition setTrainSpeed ]
∀ sb1 : [Link], t : [Link], sp : [Link],
s : State,
con : [Link] •
getPointPosition(sb1,setTrainSpeed(t,sp,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
sp ≤ [Link](t,con),
[ getPointPosition setTrainPosition ]
∀ sb1 : [Link], t : [Link], pos : [Link],
s : State,
con : [Link] •
getPointPosition(sb1,setTrainPosition(t,pos,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
∼trainPositionOccupied(t,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t,s),s,con) ∧
train pos ok(t,pos,s,con),
[ getPointPosition setTrainDirection ]
∀ sb1 : [Link], t : [Link], dir : [Link],
s : State,
F.1 Initial model 295
con : [Link] •
getPointPosition(sb1,setTrainDirection(t,dir,s),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
(
getTrainSpeed(t,s) = 0.0 ∨
getTrainDirection(t,s) = dir
),
/∗ getPointTicks gen ∗/
[ getPointTicks setPointPosition ]
∀ sb1,sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setPointPosition(sb2,pp,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getPointTicks setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
if(sb1 = sb2)
then
ticks
else
getPointTicks(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getPointTicks setBarrierPosition ]
∀ sb1,sb2 : [Link], bp : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getPointTicks setSignalStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
296 RSL modules
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getPointTicks setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setSensorStatus(sb2,ss,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
sensor guard(sb2,ss,con,s) ∧
pointStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
[ getPointTicks setTrainAcc ]
∀ sb1 : [Link], t : [Link], acc : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setTrainAcc(t,acc,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
acc ≤ [Link](t,con) ∧
[Link](t,con) ≤ acc,
[ getPointTicks setTrainSpeed ]
∀ sb1 : [Link], t : [Link], sp : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setTrainSpeed(t,sp,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
sp ≤ [Link](t,con),
[ getPointTicks setTrainPosition ]
∀ sb1 : [Link], t : [Link], pos : [Link],
s : State,
con : [Link] •
getPointTicks(sb1,setTrainPosition(t,pos,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
∼trainPositionOccupied(t,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t,s),s,con) ∧
train pos ok(t,pos,s,con),
[ getPointTicks setTrainDirection ]
∀ sb1 : [Link], t : [Link], dir : [Link],
s : State,
con : [Link] •
F.1 Initial model 297
getPointTicks(sb1,setTrainDirection(t,dir,s),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
(
getTrainSpeed(t,s) = 0.0 ∨
getTrainDirection(t,s) = dir
),
/∗ getBarrierPosition gen ∗/
[ getBarrierPosition setPointPosition ]
∀ sb1,sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setPointPosition(sb2,pp,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getBarrierPosition setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getBarrierPosition setBarrierPosition ]
∀ s : State, sb1,sb2 : [Link], bp : [Link],
con : [Link] •
getBarrierPosition(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
if(sb1 = sb2)
then
bp
else
getBarrierPosition(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getBarrierPosition setSignalStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
298 RSL modules
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getBarrierPosition setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setSensorStatus(sb2,ss,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
sensor guard(sb2,ss,con,s) ∧
crossingStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
[ getBarrierPosition setTrainAcc ]
∀ sb1 : [Link], t : [Link], acc : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setTrainAcc(t,acc,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
acc ≤ [Link](t,con) ∧
[Link](t,con) ≤ acc,
[ getBarrierPosition setTrainSpeed ]
∀ sb1 : [Link], t : [Link], sp : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setTrainSpeed(t,sp,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
sp ≤ [Link](t,con),
[ getBarrierPosition setTrainPosition ]
∀ sb1 : [Link], t : [Link], pos : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setTrainPosition(t,pos,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
∼trainPositionOccupied(t,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t,s),s,con) ∧
train pos ok(t,pos,s,con),
[ getBarrierPosition setTrainDirection ]
∀ sb1 : [Link], t : [Link], dir : [Link],
s : State,
con : [Link] •
getBarrierPosition(sb1,setTrainDirection(t,dir,s),con) ≡
getBarrierPosition(sb1,s,con)
F.1 Initial model 299
/∗ getSignalStatus gen ∗/
[ getSignalStatus setPointPosition ]
∀ sb1,sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getSignalStatus(sb1,setPointPosition(sb2,pp,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getSignalStatus setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getSignalStatus(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getSignalStatus setBarrierPosition ]
∀ s : State, sb1,sb2 : [Link], bp : [Link],
con : [Link] •
getSignalStatus(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getSignalStatus setSignalStatus ]
∀ s : State, sb1,sb2 : [Link], ss : [Link],
con : [Link] •
getSignalStatus(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
if(sb1 = sb2)
then
ss
else
getSignalStatus(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
300 RSL modules
crossingStateExists(sb2,s,con),
[ getSignalStatus setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getSignalStatus(sb1,setSensorStatus(sb2,ss,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
sensor guard(sb2,ss,con,s) ∧
crossingStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
[ getSignalStatus setTrainAcc ]
∀ sb1 : [Link], t : [Link], acc : [Link],
s : State,
con : [Link] •
getSignalStatus(sb1,setTrainAcc(t,acc,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
acc ≤ [Link](t,con) ∧
[Link](t,con) ≤ acc,
[ getSignalStatus setTrainSpeed ]
∀ sb1 : [Link], t : [Link], sp : [Link],
s : State,
con : [Link] •
getSignalStatus(sb1,setTrainSpeed(t,sp,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
sp ≤ [Link](t,con),
[ getSignalStatus setTrainPosition ]
∀ sb1 : [Link], t : [Link], pos : [Link],
s : State,
con : [Link] •
getSignalStatus(sb1,setTrainPosition(t,pos,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
trainStateExists(t,s) ∧
∼trainPositionOccupied(t,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t,s),s,con) ∧
train pos ok(t,pos,s,con),
[ getSignalStatus setTrainDirection ]
∀ sb1 : [Link], t : [Link], dir : [Link],
s : State,
con : [Link] •
getSignalStatus(sb1,setTrainDirection(t,dir,s),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
F.1 Initial model 301
trainStateExists(t,s) ∧
(
getTrainSpeed(t,s) = 0.0 ∨
getTrainDirection(t,s) = dir
),
/∗ getSensorStatus gen ∗/
[ getSensorStatus setPointPosition ]
∀ sb1,sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getSensorStatus(sb1,setPointPosition(sb2,pp,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getSensorStatus setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getSensorStatus(sb1,setPointTicks(sb2,ticks,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
pointStateExists(sb2,s,con),
[ getSensorStatus setBarrierPosition ]
∀ s : State, sb1,sb2 : [Link], bp : [Link],
con : [Link] •
getSensorStatus(sb1,setBarrierPosition(sb2,bp,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
crossingStateExists(sb2,s,con),
[ getSensorStatus setSignalStatus ]
∀ s : State, sb1,sb2 : [Link], ss : [Link],
con : [Link] •
getSensorStatus(sb1,setSignalStatus(sb2,ss,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
crossingStateExists(sb2,s,con),
[ getSensorStatus setSensorStatus ]
∀ s : State, sb1,sb2 : [Link], ss : [Link],
con : [Link] •
getSensorStatus(sb1,setSensorStatus(sb2,ss,s,con)) ≡
if(sb1 = sb2)
then
ss
else
getSensorStatus(sb1,s)
end
302 RSL modules
[ getSensorStatus setTrainAcc ]
∀ sb1 : [Link], t : [Link], acc : [Link],
s : State,
con : [Link] •
getSensorStatus(sb1,setTrainAcc(t,acc,s,con)) ≡
getSensorStatus(sb1,s)
pre sensorStateExists(sb1,s) ∧
trainStateExists(t,s) ∧
acc ≤ [Link](t,con) ∧
[Link](t,con) ≤ acc,
[ getSensorStatus setTrainSpeed ]
∀ sb1 : [Link], t : [Link], sp : [Link],
s : State,
con : [Link] •
getSensorStatus(sb1,setTrainSpeed(t,sp,s,con)) ≡
getSensorStatus(sb1,s)
pre sensorStateExists(sb1,s) ∧
trainStateExists(t,s) ∧
sp ≤ [Link](t,con),
[ getSensorStatus setTrainPosition ]
∀ sb1 : [Link], t : [Link], pos : [Link],
s : State,
con : [Link] •
getSensorStatus(sb1,setTrainPosition(t,pos,s,con)) ≡
getSensorStatus(sb1,s)
pre sensorStateExists(sb1,s) ∧
trainStateExists(t,s) ∧
∼trainPositionOccupied(t,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t,s),s,con) ∧
train pos ok(t,pos,s,con),
[ getSensorStatus setTrainDirection ]
∀ sb1 : [Link], t : [Link], dir : [Link],
s : State,
con : [Link] •
getSensorStatus(sb1,setTrainDirection(t,dir,s)) ≡
getSensorStatus(sb1,s)
pre sensorStateExists(sb1,s) ∧
trainStateExists(t,s) ∧
(
getTrainSpeed(t,s) = 0.0 ∨
getTrainDirection(t,s) = dir
),
/∗ getTrainAcc gen ∗/
[ getTrainAcc setPointPosition ]
∀ t1 : [Link], sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setPointPosition(sb2,pp,s,con)) ≡
F.1 Initial model 303
getTrainAcc(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getTrainAcc setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getTrainAcc(sb1,setPointTicks(sb2,ticks,s,con)) ≡
getTrainAcc(sb1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(sb1,s) ∧
pointStateExists(sb2,s,con),
[ getTrainAcc setBarrierPosition ]
∀ t1 : [Link], sb2 : [Link], bp : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setBarrierPosition(sb2,bp,s,con)) ≡
getTrainAcc(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainAcc setSignalStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setSignalStatus(sb2,ss,s,con)) ≡
getTrainAcc(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainAcc setSensorStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setSensorStatus(sb2,ss,s,con)) ≡
getTrainAcc(t1,s)
pre sensor guard(sb2,ss,con,s) ∧
trainStateExists(t1,s) ∧
sensorStateExists(sb2,s),
[ getTrainAcc setTrainAcc ]
∀ t1,t2 : [Link], acc : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setTrainAcc(t2,acc,s,con)) ≡
if(t1 = t2)
then
acc
else
getTrainAcc(t1,s)
end
304 RSL modules
[ getTrainAcc setTrainSpeed ]
∀ t1,t2 : [Link], sp : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setTrainSpeed(t2,sp,s,con)) ≡
getTrainAcc(t1,s)
pre trainStateExists(t1,s) ∧
trainStateExists(t2,s) ∧
sp ≤ [Link](t2,con),
[ getTrainAcc setTrainPosition ]
∀ t1,t2 : [Link], pos : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setTrainPosition(t2,pos,s,con)) ≡
getTrainAcc(t1,s)
pre trainStateExists(t1,s) ∧
trainStateExists(t2,s) ∧
∼trainPositionOccupied(t2,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t2,s),s,con) ∧
train pos ok(t2,pos,s,con),
[ getTrainAcc setTrainDirection ]
∀ t1,t2 : [Link], dir : [Link],
s : State,
con : [Link] •
getTrainAcc(t1,setTrainDirection(t2,dir,s)) ≡
getTrainAcc(t1,s)
pre trainStateExists(t1,s) ∧
trainStateExists(t2,s) ∧
(
getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir
),
/∗ getTrainSpeed gen ∗/
[ getTrainSpeed setPointPosition ]
∀ t1 : [Link], sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getTrainSpeed(t1,setPointPosition(sb2,pp,s,con)) ≡
getTrainSpeed(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getTrainSpeed setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
F.1 Initial model 305
getTrainSpeed(sb1,setPointTicks(sb2,ticks,s,con)) ≡
getTrainSpeed(sb1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(sb1,s) ∧
pointStateExists(sb2,s,con),
[ getTrainSpeed setBarrierPosition ]
∀ t1 : [Link], sb2 : [Link], bp : [Link],
s : State,
con : [Link] •
getTrainSpeed(t1,setBarrierPosition(sb2,bp,s,con)) ≡
getTrainSpeed(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainSpeed setSignalStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainSpeed(t1,setSignalStatus(sb2,ss,s,con)) ≡
getTrainSpeed(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainSpeed setSensorStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainSpeed(t1,setSensorStatus(sb2,ss,s,con)) ≡
getTrainSpeed(t1,s)
pre sensor guard(sb2,ss,con,s) ∧
trainStateExists(t1,s) ∧
sensorStateExists(sb2,s),
[ getTrainSpeed setTrainAcc ]
∀ t1,t2 : [Link], acc : [Link],
s : State,
con : [Link] •
getTrainSpeed(t1,setTrainAcc(t2,acc,s,con)) ≡
getTrainSpeed(t1,s)
pre acc ≤ [Link](t2,con) ∧
[Link](t2,con) ≤ acc ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainSpeed setTrainSpeed ]
∀ s : State, t1,t2 : [Link], sp : [Link],
con : [Link] •
getTrainSpeed(t1,setTrainSpeed(t2,sp,s,con)) ≡
if(t1 = t2)
then
sp
else
getTrainSpeed(t1,s)
end
306 RSL modules
pre sp ≤ [Link](t2,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainSpeed setTrainPosition ]
∀ t1,t2 : [Link], pos : [Link],
s : State,
con : [Link] •
getTrainSpeed(t1,setTrainPosition(t2,pos,s,con)) ≡
getTrainSpeed(t1,s)
pre trainStateExists(t1,s) ∧
trainStateExists(t2,s) ∧
∼trainPositionOccupied(t2,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t2,s),s,con) ∧
train pos ok(t2,pos,s,con),
[ getTrainSpeed setTrainDirection ]
∀ t1,t2 : [Link], dir : [Link],
s : State,
con : [Link] •
getTrainSpeed(t1,setTrainDirection(t2,dir,s)) ≡
getTrainSpeed(t1,s)
pre trainStateExists(t1,s) ∧
trainStateExists(t2,s) ∧
(
getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir
),
/∗ getTrainPosition gen ∗/
[ getTrainPosition setPointPosition ]
∀ t1 : [Link], sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getTrainPosition(t1,setPointPosition(sb2,pp,s,con)) ≡
getTrainPosition(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getTrainPosition setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getTrainPosition(sb1,setPointTicks(sb2,ticks,s,con)) ≡
getTrainPosition(sb1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(sb1,s) ∧
pointStateExists(sb2,s,con),
[ getTrainPosition setBarrierPosition ]
∀ t1 : [Link], sb2 : [Link], bp : [Link],
s : State,
con : [Link] •
getTrainPosition(t1,setBarrierPosition(sb2,bp,s,con)) ≡
F.1 Initial model 307
getTrainPosition(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainPosition setSignalStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainPosition(t1,setSignalStatus(sb2,ss,s,con)) ≡
getTrainPosition(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainPosition setSensorStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainPosition(t1,setSensorStatus(sb2,ss,s,con)) ≡
getTrainPosition(t1,s)
pre sensor guard(sb2,ss,con,s) ∧
trainStateExists(t1,s) ∧
sensorStateExists(sb2,s),
[ getTrainPosition setTrainAcc ]
∀ t1,t2 : [Link], acc : [Link],
s : State,
con : [Link] •
getTrainPosition(t1,setTrainAcc(t2,acc,s,con)) ≡
getTrainPosition(t1,s)
pre acc ≤ [Link](t2,con) ∧
[Link](t2,con) ≤ acc ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainPosition setTrainSpeed ]
∀ s : State, t1,t2 : [Link], sp : [Link],
con : [Link] •
getTrainPosition(t1,setTrainSpeed(t2,sp,s,con)) ≡
getTrainPosition(t1,s)
pre sp ≤ [Link](t2,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainPosition setTrainPosition ]
∀ s : State, t1,t2 : [Link], tp : [Link],
con : [Link] •
getTrainPosition(t1,setTrainPosition(t2,tp,s,con)) ≡
if(t1 = t2)
then
tp
else
getTrainPosition(t1,s)
end
pre ∼trainPositionOccupied(t2,tp,s,con) ∧
∼tpDerailed(tp,getTrainDirection(t2,s),s,con) ∧
308 RSL modules
[ getTrainPosition setTrainDirection ]
∀ t1,t2 : [Link], dir : [Link],
s : State,
con : [Link] •
getTrainPosition(t1,setTrainDirection(t2,dir,s)) ≡
getTrainPosition(t1,s)
pre trainStateExists(t1,s) ∧
trainStateExists(t2,s) ∧
(
getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir
),
/∗ getTrainDirection gen ∗/
[ getTrainDirection setPointPosition ]
∀ t1 : [Link], sb2 : [Link], pp : [Link],
s : State,
con : [Link] •
getTrainDirection(t1,setPointPosition(sb2,pp,s,con)) ≡
getTrainDirection(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
pointStateExists(sb2,s,con) ∧
∼trainOnJunction(sb2,con,s),
[ getTrainDirection setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : State,
con : [Link] •
getTrainDirection(sb1,setPointTicks(sb2,ticks,s,con)) ≡
getTrainDirection(sb1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(sb1,s) ∧
pointStateExists(sb2,s,con),
[ getTrainDirection setBarrierPosition ]
∀ t1 : [Link], sb2 : [Link], bp : [Link],
s : State,
con : [Link] •
getTrainDirection(t1,setBarrierPosition(sb2,bp,s,con)) ≡
getTrainDirection(t1,s)
pre [Link](sb2,con) = [Link] ∧
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainDirection setSignalStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainDirection(t1,setSignalStatus(sb2,ss,s,con)) ≡
getTrainDirection(t1,s)
pre [Link](sb2,con) = [Link] ∧
F.1 Initial model 309
trainStateExists(t1,s) ∧
crossingStateExists(sb2,s,con),
[ getTrainDirection setSensorStatus ]
∀ t1 : [Link], sb2 : [Link], ss : [Link],
s : State,
con : [Link] •
getTrainDirection(t1,setSensorStatus(sb2,ss,s,con)) ≡
getTrainDirection(t1,s)
pre sensor guard(sb2,ss,con,s) ∧
trainStateExists(t1,s) ∧
sensorStateExists(sb2,s),
[ getTrainDirection setTrainAcc ]
∀ t1,t2 : [Link], acc : [Link],
s : State,
con : [Link] •
getTrainDirection(t1,setTrainAcc(t2,acc,s,con)) ≡
getTrainDirection(t1,s)
pre acc ≤ [Link](t2,con) ∧
[Link](t2,con) ≤ acc ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainDirection setTrainSpeed ]
∀ s : State, t1,t2 : [Link], sp : [Link],
con : [Link] •
getTrainDirection(t1,setTrainSpeed(t2,sp,s,con)) ≡
getTrainDirection(t1,s)
pre sp ≤ [Link](t2,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainDirection setTrainPosition ]
∀ s : State, t1,t2 : [Link], pos : [Link],
con : [Link] •
getTrainDirection(t1,setTrainPosition(t2,pos,s,con)) ≡
getTrainDirection(t1,s)
pre ∼trainPositionOccupied(t2,pos,s,con) ∧
∼tpDerailed(pos,getTrainDirection(t2,s),s,con) ∧
train pos ok(t2,pos,s,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainDirection setTrainDirection ]
∀ s : State, t1,t2 : [Link], dir : [Link]•
getTrainDirection(t1,setTrainDirection(t2,dir,s)) ≡
if(t1 = t2)
then
dir
else
getTrainDirection(t1,s)
end
pre (getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
310 RSL modules
[ gen wf setPointPosition ]
∀ p : [Link], pp : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](p,con) = [Link] ∧
∼trainOnJunction(p,con,s)
⇒
is wf(setPointPosition(p,pp,s,con),con),
[ gen wf setPointTicks ]
∀ p : [Link], ticks : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](p,con) = [Link]
⇒
is wf(setPointTicks(p,ticks,s,con),con),
[ gen wf setBarrierPosition ]
∀ cr : [Link], bp : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](cr,con) = [Link]
⇒
is wf(setBarrierPosition(cr,bp,s,con),con),
[ gen wf setSignalStatus ]
∀ cr : [Link], ss : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](cr,con) = [Link]
⇒
is wf(setSignalStatus(cr,ss,s,con),con),
[ gen wf setSensorStatus ]
∀ sen : [Link], ss : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
sensor guard(sen,ss,con,s)
⇒
is wf(setSensorStatus(sen,ss,s,con),con),
[ gen wf setTrainAcc ]
∀ t : [Link], acc : [Link],
con : [Link], s : State •
is wf(s,con) ∧
F.1 Initial model 311
acc ≤ [Link](t,con) ∧
[Link](t,con) ≤ acc
⇒
is wf(setTrainAcc(t,acc,s,con),con),
[ gen wf setTrainSpeed ]
∀ t : [Link], sp : [Link],
con : [Link], s : State •
is wf(s,con) ∧
sp ≤ [Link](t,con)
⇒
is wf(setTrainSpeed(t,sp,s,con),con),
[ gen wf setTrainPosition ]
∀ t : [Link], pos : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
∼trainPositionOccupied(t,pos,s,con) ∧
train pos ok(t,pos,s,con)
⇒
is wf(setTrainPosition(t,pos,s,con),con),
[ gen wf setTrainDirection ]
∀ t : [Link], dir : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
(
getTrainSpeed(t,s) = 0.0 ∨
getTrainDirection(t,s) = dir
)
⇒
is wf(setTrainDirection(t,dir,s),con)
end
F.1.4 Control
context: AA Dynamics0
scheme AA Control0(T : AA Types0, S : AA Statics0(T),
D : AA Dynamics0(T,S)) =
class
type
ControlState
value
initControlState : ControlState,
∼
getSBCCLineRes : [Link] × ControlState → [Link],
∼
getSBCCBranchRes : [Link] × ControlState → [Link],
∼
getLastSensorStatus : [Link] × ControlState →
[Link],
setLastSensorStatus : [Link] × [Link] ×
∼
ControlState → ControlState,
∼
getNextSBCCMsg : [Link] × ControlState →
[Link] × ControlState,
storeSBCCMsg : [Link] × [Link] ×
∼
ControlState → ControlState,
∼
getSBCCPrepRes : [Link] × ControlState → [Link],
setSBCCPrepRes : [Link] × [Link] ×
∼
ControlState → ControlState,
/∗ Processes ∗/
tick : [Link] × ControlState × [Link] ×
∼
[Link] → ControlState × [Link]
tick(tick,cs,ds,con) ≡
(
let
tSet = {t | t : [Link]},
sbSet = {sb | sb : [Link]},
(cs,ds) = tickTCCs(tSet,tick,cs,ds,con),
cs = tickSBCCs(sbSet,tick,cs,ds,con)
in
(cs,ds)
end
),
/∗ Auxiliary ∗/
∼
removeSBCCLineRes : [Link] × ControlState → ControlState
removeSBCCLineRes(sb,cs) ≡
setSBCCLineRes(sb,[Link],cs),
∼
removeSBCCBranchRes : [Link] × ControlState → ControlState
removeSBCCBranchRes(sb,cs) ≡
setSBCCBranchRes(sb,[Link],cs),
∼
removeSBCCPrepRes : [Link] × ControlState → ControlState
removeSBCCPrepRes(sb,cs) ≡
setSBCCPrepRes(sb,[Link],cs),
∼
isPreparing : [Link] × ControlState → Bool
isPreparing(sb,cs) ≡
case getSBCCPrepRes(sb,cs) of
[Link] → false,
→ true
end,
∼
comService : [Link] × ControlState → ControlState
comService(comMsg,cs) ≡
case [Link](comMsg) of
[Link](sb) → sbccMsgReceiver(sb,comMsg,cs),
[Link](t) → tccMsgReceiver(t,comMsg,cs)
end,
∼
ControlState → ControlState
tccMsgReceiver(t,comMsg,cs) ≡
let
resp = [Link](comMsg)
in
case resp of
[Link](resGranted) →
(
let
cs = setTCCRequesting(t,false,cs)
in
if(resGranted)
then
setTCCRes(t,true,cs)
else
cs
end
end
),
→ cs
end
end,
/∗ Processes ∗/
tccProcess : [Link] × [Link] × ControlState ×
∼
[Link] × [Link] →
ControlState × [Link]
tccProcess(t,tick,cs,ds,con) ≡
let
(cs,ds) = checkSpeed(t,tick,cs,ds,con),
cs = clearRes(t,cs,ds),
(cs,ds) = handleRes(t,cs,ds,con)
in
(cs,ds)
end,
checkDeceleration(t,cs,ds,con)
end
else /∗ Train on segment and perhaps an ESA ∗/
let
tp = [Link](t,ds),
frontSeg = [Link](isSeg),
segMaxSpeed = [Link](frontSeg,con)
in
if (ts > segMaxSpeed ∨ ts > trainMaxSpeed)
then
decelerateTrain(t,cs,ds,con)
else
checkDeceleration(t,cs,ds,con)
end
end
end
end, /∗ let ∗/
(cs,ds)
end,
∼
clearRes : [Link] × ControlState × [Link] →
ControlState
clearRes(t,cs,ds) ≡
if(∼[Link]([Link](t,ds)))
then
setTCCRes(t,false,cs)
else
cs
end,
(sendTCCReq(t,[Link](esa,con),dir,cs),ds)
end
),
[Link](seg) →
(
(sendTCCReq(t,[Link](seg,dir,con),dir,cs),ds)
)
end /∗ case ∗/
end, /∗ let ∗/
cs
end
),
→ cs
end,
[Link] →
(
(cs,[Link](sb,[Link],ds,con))
),
→ (cs,ds)
end
end,
[Link] →
(
case [Link](res) of
[Link] →
(
let
ds = [Link](sb,[Link],ds,con)
in
(cs,ds)
end
),
[Link] →
(
let
ds = [Link](sb,[Link],ds,con)
in
(cs,ds)
end
)
end
),
→ (cs,ds)
end
end,
case [Link](sb,con) of
[Link] →
(
let
[Link](lineRes) = getSBCCLineRes(sb,cs),
endDir = [Link](sb,con)
in
if ([Link](lineRes) = endDir)
then
let
cs = removeSBCCLineRes(sb,cs)
in
sendLDeResMsg(sb,[Link](sb,con),cs)
end
else
cs
end /∗ if ∗/
end /∗ let ∗/
),
[Link] →
(
let
[Link](lineRes) = getSBCCLineRes(sb,cs),
pointDir = [Link](sb,con)
in
if ([Link](lineRes) = pointDir)
then
let
cs = removeSBCCLineRes(sb,cs)
in
sendLDeResMsg(sb,[Link](sb,con),cs)
end
else
sendBDeResMsg(sb,[Link](sb,con),cs)
end /∗ if ∗/
end /∗ let ∗/
)
end /∗ case ∗/
pre [Link](sb,con),
∼
sendLBDeResMsg : [Link] × [Link] × ControlState →
ControlState
sendLBDeResMsg(thisSB,remoteSB,cs) ≡
sendSBCCMsg(thisSB,[Link](remoteSB),[Link],cs),
∼
sendLDeResMsg : [Link] × [Link] × ControlState →
ControlState
sendLDeResMsg(thisSB,remoteSB,cs) ≡
sendSBCCMsg(thisSB,[Link](remoteSB),[Link],cs),
∼
sendBDeResMsg : [Link] × [Link] × ControlState →
ControlState
sendBDeResMsg(thisSB,remoteSB,cs) ≡
sendSBCCMsg(thisSB,[Link](remoteSB),[Link],cs),
∼
ControlState → ControlState
sendLBResMsg(thisSB,remoteSB,aRes,cs) ≡
sendSBCCMsg(thisSB,[Link](remoteSB),
[Link](aRes),cs),
[Link]( ) →
(
let
(cs,retMsg) = handleSBCCMsg(sb,msg,cs)
in
case retMsg of
[Link](aMsg) →
sendSBCCMsg(sb,sender,aMsg,cs),
→ cs
end
end
)
end /∗ case ∗/
),
→ cs /∗ no message to process ∗/
end
end, /∗ let ∗/
∼
handleSBCCMsg : [Link] × [Link] × ControlState →
ControlState × [Link]
handleSBCCMsg(sb,msg,cs) ≡
case msg of
/∗ Request ∗/
[Link]( ) → handleLBReq(sb,msg,cs),
322 RSL modules
/∗ Response ∗/
[Link]( ) → handleLBResp(sb,msg,cs),
/∗ De reservation ∗/
[Link] → handleDeResMsg(sb,msg,cs),
[Link] → handleDeResMsg(sb,msg,cs),
[Link] → handleDeResMsg(sb,msg,cs)
end,
end
else
if (lineFree(sb,cs))
then
let
cs = setSBCCLineRes(sb,[Link](res),cs),
cs = sendLBResMsg(sb,
[Link](sb,con),res,cs)
in
([Link],cs,ds)
end
else
([Link]([Link](false)),cs,ds)
end
end
),
→ /∗ PLAINSB, CROSSINGSB ∗/
(
let
(cs,ds) = prepareSeg(sb,res,cs,ds,con)
in
([Link],cs,ds)
end
)
end /∗ case ∗/
end, /∗ let ∗/
∼
lineFree : [Link] × ControlState → Bool
lineFree(sb,cs) ≡
(getSBCCLineRes(sb,cs) = [Link]),
/∗ case(msg)
lb → deres line; deres branch
l → deres line;
b → deres branch;
∗/
∼
handleDeResMsg : [Link] × [Link] × ControlState →
ControlState × [Link]
handleDeResMsg(sb,msg,cs) ≡
case msg of
[Link] →
(
let
cs = removeSBCCLineRes(sb,cs),
cs = removeSBCCBranchRes(sb,cs)
in
(cs,[Link])
end
),
[Link] →
(
let
cs = removeSBCCLineRes(sb,cs)
F.1 Initial model 325
in
(cs,[Link])
end
),
[Link] →
(
let
cs = removeSBCCBranchRes(sb,cs)
in
(cs,[Link])
end
)
end,
/∗ Wellformednes ∗/
is wf : ControlState × [Link] × [Link] → Bool
is wf(cs,ds,con) ≡
[Link] wf(ds,con) ∧
tcc has state(cs) ∧
sbcc has state(cs),
/∗∗
∗ Defines that the control system and all its
∗ components must be consistent e.g. the information
∗ stored in the control system must reflect the physical
∗ world and unintended states must not occur.
∗
∗ Also the physical world must abide by
∗ the rules of the control system.
*∗/
consistent : ControlState × [Link] × [Link] → Bool
consistent(cs,ds,con) ≡
is wf(cs,ds,con) ∧
train on branch dir(ds,con) ∧
tcc hasRes passedResPoint(cs,ds,con) ∧
sbcc res wf(cs,con) ∧
position branch sbcc res wf(cs,ds,con) ∧
tcc res branch wf(cs,ds,con) ∧
position sl sbcc res wf(cs,ds,con) ∧
barrierPos signalStatus Consistent(ds,con),
326 RSL modules
axiom
/∗ The initial state has to be wellformed and
fullfill the initial state requirements ∗/
[ initial state ]
initReq(initControlState,[Link],[Link]),
/∗∗
∗ Observer generator axioms
*∗/
/∗ getSBCCLineRes gen ∗/
[ getSBCCLineRes setSBCCLineRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,
setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
if(sb1 = sb2)
then
[Link](sbRes)
else
getSBCCLineRes(sb1,cs)
end,
[ getSBCCLineRes removeSBCCLineRes ]
∀ sb1,sb2 : [Link], cs : ControlState •
getSBCCLineRes(sb1,removeSBCCLineRes(sb2,cs)) ≡
if(sb1 = sb2)
then
[Link]
else
getSBCCLineRes(sb1,cs)
end,
[ getSBCCLineRes setSBCCBranchRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,
setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
getSBCCLineRes(sb1,cs),
[ getSBCCLineRes setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,setLastSensorStatus(sb2,ss,cs)) ≡
getSBCCLineRes(sb1,cs),
330 RSL modules
[ getSBCCLineRes storeSBCCMsg ]
∀ sb1,sb2 : [Link], cm : [Link],
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,storeSBCCMsg(sb2,cm,cs)) ≡
getSBCCLineRes(sb1,cs),
[ getSBCCLineRes setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
getSBCCLineRes(sb1,cs),
[ getSBCCLineRes setTCCRes ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,setTCCRes(sb2,b,cs)) ≡
getSBCCLineRes(sb1,cs),
[ getSBCCLineRes setTCCRequesting ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,setTCCRequesting(sb2,b,cs)) ≡
getSBCCLineRes(sb1,cs),
[ getSBCCLineRes setTrainDecelerating ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCLineRes(sb1,setTrainDecelerating(sb2,b,cs)) ≡
getSBCCLineRes(sb1,cs),
/∗ getSBCCBranchRes gen ∗/
[ getSBCCBranchRes setSBCCLineRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
getSBCCBranchRes(sb1,
setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
getSBCCBranchRes(sb1,cs),
[ getSBCCBranchRes setSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState,
sbRes : [Link],
con : [Link] •
getSBCCBranchRes(sb1,
setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
if(sb1 = sb2)
then
[Link](sbRes)
else
getSBCCBranchRes(sb1,cs)
F.1 Initial model 331
end,
[ getSBCCBranchRes removeSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState •
getSBCCBranchRes(sb1,removeSBCCBranchRes(sb2,cs)) ≡
if(sb1 = sb2)
then
[Link]
else
getSBCCBranchRes(sb1,cs)
end,
[ getSBCCBranchRes setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState,
con : [Link] •
getSBCCBranchRes(sb1,setLastSensorStatus(sb2,ss,cs)) ≡
getSBCCBranchRes(sb1,cs),
[ getSBCCBranchRes storeSBCCMsg ]
∀ sb1,sb2 : [Link], cm : [Link],
cs : ControlState,
con : [Link] •
getSBCCBranchRes(sb1,storeSBCCMsg(sb2,cm,cs)) ≡
getSBCCBranchRes(sb1,cs),
[ getSBCCBranchRes setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
getSBCCBranchRes(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
getSBCCBranchRes(sb1,cs),
[ getSBCCBranchRes setTCCRes ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCBranchRes(sb1,setTCCRes(sb2,b,cs)) ≡
getSBCCBranchRes(sb1,cs),
[ getSBCCBranchRes setTCCRequesting ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCBranchRes(sb1,setTCCRequesting(sb2,b,cs)) ≡
getSBCCBranchRes(sb1,cs),
[ getSBCCBranchRes setTrainDecelerating ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCBranchRes(sb1,setTrainDecelerating(sb2,b,cs)) ≡
getSBCCBranchRes(sb1,cs),
/∗ getLastSensorStatus gen ∗/
[ getLastSensorStatus setSBCCLineRes ]
332 RSL modules
[ getLastSensorStatus setSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState,
sbRes : [Link],
con : [Link] •
getLastSensorStatus(sb1,
setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
getLastSensorStatus(sb1,cs),
[ getLastSensorStatus setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState •
getLastSensorStatus(sb1,
setLastSensorStatus(sb2,ss,cs)) ≡
if(sb1 = sb2)
then
ss
else
getLastSensorStatus(sb1,cs)
end,
[ getLastSensorStatus storeSBCCMsg ]
∀ sb1,sb2 : [Link], cm : [Link],
cs : ControlState,
con : [Link] •
getLastSensorStatus(sb1,storeSBCCMsg(sb2,cm,cs)) ≡
getLastSensorStatus(sb1,cs),
[ getLastSensorStatus setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
getLastSensorStatus(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
getLastSensorStatus(sb1,cs),
[ getLastSensorStatus setTCCRes ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getLastSensorStatus(sb1,setTCCRes(sb2,b,cs)) ≡
getLastSensorStatus(sb1,cs),
[ getLastSensorStatus setTCCRequesting ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getLastSensorStatus(sb1,setTCCRequesting(sb2,b,cs)) ≡
getLastSensorStatus(sb1,cs),
[ getLastSensorStatus setTrainDecelerating ]
∀ sb1,sb2 : [Link], b : Bool,
F.1 Initial model 333
cs : ControlState,
con : [Link] •
getLastSensorStatus(sb1,
setTrainDecelerating(sb2,b,cs)) ≡
getLastSensorStatus(sb1,cs),
/∗ getNextSBCCMsg gen ∗/
[ getNextSBCCMsg setSBCCLineRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
getNextSBCCMsg(sb1,
setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
getNextSBCCMsg(sb1,cs),
[ getNextSBCCMsg setSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState,
sbRes : [Link],
con : [Link] •
getNextSBCCMsg(sb1,
setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
getNextSBCCMsg(sb1,cs),
[ getNextSBCCMsg setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState •
getNextSBCCMsg(sb1,setLastSensorStatus(sb2,ss,cs)) ≡
getNextSBCCMsg(sb1,cs),
[ getNextSBCCMsg setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
getNextSBCCMsg(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
getNextSBCCMsg(sb1,cs),
[ getNextSBCCMsg setTCCRes ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getNextSBCCMsg(sb1,setTCCRes(sb2,b,cs)) ≡
getNextSBCCMsg(sb1,cs),
[ getNextSBCCMsg setTCCRequesting ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getNextSBCCMsg(sb1,setTCCRequesting(sb2,b,cs)) ≡
getNextSBCCMsg(sb1,cs),
[ getNextSBCCMsg setTrainDecelerating ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getNextSBCCMsg(sb1,setTrainDecelerating(sb2,b,cs)) ≡
getNextSBCCMsg(sb1,cs),
334 RSL modules
/∗ getSBCCPrepRes gen ∗/
[ getSBCCPrepRes setSBCCLineRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
getSBCCPrepRes(sb1,setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
getSBCCPrepRes(sb1,cs),
[ getSBCCPrepRes setSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState,
sbRes : [Link],
con : [Link] •
getSBCCPrepRes(sb1,
setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
getSBCCPrepRes(sb1,cs),
[ getSBCCPrepRes setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState •
getSBCCPrepRes(sb1,setLastSensorStatus(sb2,ss,cs)) ≡
getSBCCPrepRes(sb1,cs),
[ getSBCCPrepRes storeSBCCMsg ]
∀ sb1,sb2 : [Link], cm : [Link],
cs : ControlState,
con : [Link] •
getSBCCPrepRes(sb1,storeSBCCMsg(sb2,cm,cs)) ≡
getSBCCPrepRes(sb1,cs),
[ getSBCCPrepRes setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
getSBCCPrepRes(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
if(sb1 = sb2)
then
hr
else
getSBCCPrepRes(sb1,cs)
end,
[ getSBCCPrepRes setTCCRes ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCPrepRes(sb1,setTCCRes(sb2,b,cs)) ≡
getSBCCPrepRes(sb1,cs),
[ getSBCCPrepRes setTCCRequesting ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCPrepRes(sb1,setTCCRequesting(sb2,b,cs)) ≡
getSBCCPrepRes(sb1,cs),
F.1 Initial model 335
[ getSBCCPrepRes setTrainDecelerating ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
getSBCCPrepRes(sb1,setTrainDecelerating(sb2,b,cs)) ≡
getSBCCPrepRes(sb1,cs),
/∗ hasTCCRes gen ∗/
[ hasTCCRes setSBCCLineRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
hasTCCRes(sb1,setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
hasTCCRes(sb1,cs),
[ hasTCCRes setSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState,
sbRes : [Link],
con : [Link] •
hasTCCRes(sb1,setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
hasTCCRes(sb1,cs),
[ hasTCCRes setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState •
hasTCCRes(sb1,setLastSensorStatus(sb2,ss,cs)) ≡
hasTCCRes(sb1,cs),
[ hasTCCRes storeSBCCMsg ]
∀ sb1,sb2 : [Link], cm : [Link],
cs : ControlState,
con : [Link] •
hasTCCRes(sb1,storeSBCCMsg(sb2,cm,cs)) ≡
hasTCCRes(sb1,cs),
[ hasTCCRes setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
hasTCCRes(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
hasTCCRes(sb1,cs),
[ hasTCCRes setTCCRes ]
∀ t1, t2 : [Link], b : Bool, cs : ControlState •
hasTCCRes(t1,setTCCRes(t2,b,cs)) ≡
if(t1 = t2)
then
b
else
hasTCCRes(t1,cs)
end,
[ hasTCCRes setTCCRequesting ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
336 RSL modules
hasTCCRes(sb1,setTCCRequesting(sb2,b,cs)) ≡
hasTCCRes(sb1,cs),
[ hasTCCRes setTrainDecelerating ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
hasTCCRes(sb1,setTrainDecelerating(sb2,b,cs)) ≡
hasTCCRes(sb1,cs),
/∗ isTCCRequesting gen ∗/
[ isTCCRequesting setSBCCLineRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
isTCCRequesting(sb1,
setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
isTCCRequesting(sb1,cs),
[ isTCCRequesting setSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState,
sbRes : [Link],
con : [Link] •
isTCCRequesting(sb1,
setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
isTCCRequesting(sb1,cs),
[ isTCCRequesting setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState •
isTCCRequesting(sb1,setLastSensorStatus(sb2,ss,cs)) ≡
isTCCRequesting(sb1,cs),
[ isTCCRequesting storeSBCCMsg ]
∀ sb1,sb2 : [Link], cm : [Link],
cs : ControlState,
con : [Link] •
isTCCRequesting(sb1,storeSBCCMsg(sb2,cm,cs)) ≡
isTCCRequesting(sb1,cs),
[ isTCCRequesting setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
isTCCRequesting(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
isTCCRequesting(sb1,cs),
[ isTCCRequesting setTCCRes ]
∀ t1, t2 : [Link], b : Bool, cs : ControlState •
isTCCRequesting(t1,setTCCRes(t2,b,cs)) ≡
isTCCRequesting(t1,cs),
[ isTCCRequesting setTCCRequesting ]
∀ t1, t2 : [Link], b : Bool, cs : ControlState •
isTCCRequesting(t1,setTCCRequesting(t2,b,cs)) ≡
if(t1 = t2)
F.1 Initial model 337
then
b
else
isTCCRequesting(t1,cs)
end,
[ isTCCRequesting setTrainDecelerating ]
∀ sb1,sb2 : [Link], b : Bool,
cs : ControlState,
con : [Link] •
isTCCRequesting(sb1,setTrainDecelerating(sb2,b,cs)) ≡
isTCCRequesting(sb1,cs),
/∗ isTrainDecelerating gen ∗/
[ isTrainDecelerating setSBCCLineRes ]
∀ sb1,sb2 : [Link], sbRes : [Link],
cs : ControlState,
con : [Link] •
isTrainDecelerating(sb1,
setSBCCLineRes(sb2,[Link](sbRes),cs)) ≡
isTrainDecelerating(sb1,cs),
[ isTrainDecelerating setSBCCBranchRes ]
∀ sb1,sb2 : [Link], cs : ControlState,
sbRes : [Link],
con : [Link] •
isTrainDecelerating(sb1,
setSBCCBranchRes(sb2,[Link](sbRes),cs)) ≡
isTrainDecelerating(sb1,cs),
[ isTrainDecelerating setLastSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
cs : ControlState •
isTrainDecelerating(sb1,
setLastSensorStatus(sb2,ss,cs)) ≡
isTrainDecelerating(sb1,cs),
[ isTrainDecelerating storeSBCCMsg ]
∀ sb1,sb2 : [Link], cm : [Link],
cs : ControlState,
con : [Link] •
isTrainDecelerating(sb1,storeSBCCMsg(sb2,cm,cs)) ≡
isTrainDecelerating(sb1,cs),
[ isTrainDecelerating setSBCCPrepRes ]
∀ sb1,sb2 : [Link], hr : [Link],
cs : ControlState,
con : [Link] •
isTrainDecelerating(sb1,setSBCCPrepRes(sb2,hr,cs)) ≡
isTrainDecelerating(sb1,cs),
[ isTrainDecelerating setTCCRes ]
∀ t1, t2 : [Link], b : Bool, cs : ControlState •
isTrainDecelerating(t1,setTCCRes(t2,b,cs)) ≡
isTrainDecelerating(t1,cs),
338 RSL modules
[ isTrainDecelerating setTCCRequesting ]
∀ t1, t2 : [Link], b : Bool, cs : ControlState •
isTrainDecelerating(t1,setTCCRequesting(t2,b,cs)) ≡
isTrainDecelerating(t1,cs),
[ isTrainDecelerating setTrainDecelerating ]
∀ t1, t2 : [Link], b : Bool, cs : ControlState •
isTrainDecelerating(t1,setTrainDecelerating(t2,b,cs)) ≡
if(t1 = t2)
then
b
else
isTrainDecelerating(t1,cs)
end,
[ gen wf setSBCCLineRes ]
∀ sb : [Link], res : [Link],
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) ∈ {[Link], [Link]}
⇒
is wf(setSBCCLineRes(sb,[Link](res),cs),ds,con),
[ gen wf setSBCCBranchRes ]
∀ sb : [Link], res : [Link],
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) = [Link]
⇒
is wf(setSBCCBranchRes(sb,[Link](res),cs),ds,con),
[ gen wf removeSBCCLineRes ]
∀ sb : [Link],
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) ∈ {[Link], [Link]}
⇒
is wf(removeSBCCLineRes(sb,cs),ds,con),
[ gen wf removeSBCCBranchRes ]
∀ sb : [Link],
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con) ∧
F.1 Initial model 339
[Link](sb,con) = [Link]
⇒
is wf(removeSBCCBranchRes(sb,cs),ds,con),
[ gen wf setLastSensorStatus ]
∀ sb : [Link], ss : [Link],
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con)
⇒
is wf(setLastSensorStatus(sb,ss,cs),ds,con),
[ gen wf storeSBCCMsg ]
∀ sb : [Link],
ds : [Link], con : [Link],
cs : ControlState,
cm : [Link] •
is wf(cs,ds,con)
⇒
is wf(storeSBCCMsg(sb,cm,cs),ds,con),
[ gen wf setSBCCPrepRes ]
∀ sb : [Link],
ds : [Link], con : [Link],
cs : ControlState,
hr : [Link] •
is wf(cs,ds,con)
⇒
is wf(setSBCCPrepRes(sb,hr,cs),ds,con),
[ gen wf setTCCRes ]
∀ sb : [Link], b : Bool,
ds : [Link], con : [Link],
cs : ControlState
•
is wf(cs,ds,con)
⇒
is wf(setTCCRes(sb,b,cs),ds,con),
[ gen wf setTCCRequesting ]
∀ sb : [Link], b : Bool,
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con)
⇒
is wf(setTCCRequesting(sb,b,cs),ds,con),
[ gen wf setTrainDecelerating ]
∀ sb : [Link], b : Bool,
ds : [Link], con : [Link],
cs : ControlState •
is wf(cs,ds,con)
⇒
is wf(setTrainDecelerating(sb,b,cs),ds,con)
end
340 RSL modules
F.2.2 Statics
context: AA Types1, AA SBs1, AA Segs1, AA Trains1, AA ESAs1
scheme AA Statics1(T : AA Types1) =
class
object
SBs : AA SBs1(T),
ESAs : AA ESAs1(T),
Segs : AA Segs1(T),
Trains : AA Trains1(T)
type
/∗ Main railway line configuration type ∗/
Configuration = [Link] × [Link] ×
[Link] × [Link]
value
conf : Configuration = ([Link], [Link],
[Link], [Link]),
/∗ Observers ∗/
/∗ ESA observers ∗/
∼
getESASB : [Link] × Configuration → [Link]
getESASB(esa,(sbs,segs,esas,ts)) ≡
[Link](esa,esas),
∼
getESALength : [Link] × Configuration → [Link]
getESALength(esa,(sbs,segs,esas,ts)) ≡
[Link](esa,esas),
/∗ SB observers ∗/
∼
getSBSeg : [Link] × [Link] × Configuration →
[Link]
getSBSeg(sb,dir,(sbs,segs,esas,ts)) ≡
[Link](sb,dir,sbs),
∼
getSBType : [Link] × Configuration → [Link]
getSBType(sb,(sbs,segs,esas,ts)) ≡
[Link](sb,sbs),
/∗ Segment observers ∗/
getSegSB : [Link] × [Link] ×
∼
Configuration → [Link]
getSegSB(seg,dir,(sbs,segs,esas,ts)) ≡
[Link](seg,dir,segs),
F.2 Decomposed model 341
∼
getSegLength : [Link] × Configuration → [Link]
getSegLength(segID,(sbs,segs,esas,trains)) ≡
[Link](segID,segs),
∼
getSegMaxSpeed : [Link] × Configuration → [Link]
getSegMaxSpeed(segID,(sbs,segs,esas,trains)) ≡
[Link](segID,segs),
/∗ Train observers ∗/
∼
getTrainLength : [Link] × Configuration → [Link]
getTrainLength(tID,(sbs,segs,esas,trains)) ≡
[Link](tID,trains),
∼
getTrainMaxSpeed : [Link] × Configuration →
[Link]
getTrainMaxSpeed(t,(sbs,segs,esas,ts)) ≡
[Link](t,ts),
∼
getTrainMaxAcc : [Link] × Configuration → [Link]
getTrainMaxAcc(t,(sbs,segs,esas,ts)) ≡
[Link](t,ts),
∼
getTrainMaxDec : [Link] × Configuration → [Link]
getTrainMaxDec(t,(sbs,segs,esas,ts)) ≡
[Link](t,ts),
/∗ Auxiliary functions ∗/
/∗ Determines if a SB is a PointSB ∗/
∼
isPointSB : [Link] × Configuration → Bool
isPointSB(sbID,con) ≡
getSBType(sbID,con) = [Link],
getSingleLineGuard(getNextSB(sb,lineDir,con),lineDir,con)
end
pre isLineGuard(sb,con),
/∗ Invariants ∗/
is wf : Configuration → Bool
is wf((sbs,segs,esas,ts)) ≡
[Link] wf(sbs) ∧
[Link] wf(segs) ∧
[Link] wf(esas) ∧
[Link] wf(ts) ∧
composed is wf((sbs,segs,esas,ts)),
⇒
let
pSegs1 = getSBPointSegs(sb,con),
dir1 = [Link](pSegs1),
sb2 = getNextSB(sb,dir1,con),
pSegs2 = getSBPointSegs(sb2,con)
in
[Link](pSegs1) = [Link](pSegs2) ∧
[Link](pSegs1) = [Link](pSegs2)
end
),
∗/
brakePoint wf : Configuration → Bool
brakePoint wf(con) ≡
(
∀ t : [Link], tAcc : [Link],
brakeP, brakeL, s err : [Link],
tSpeed : [Link] •
tAcc = getTrainMaxDec(t,con) ∧
brakeP = getBrakePoint(con) ∧
tSpeed = getTrainMaxSpeed(t,con) ∧
s err = tSpeed ∗ [Link] interval ∧
brakeL = −0.5 ∗ tSpeed ∗ tSpeed / tAcc
⇒
brakeP > brakeL + s err
),
axiom
[ is wf ]
is wf(conf)
end
348 RSL modules
SBs
context: AA Types1
scheme AA SBs1(T : AA Types1) =
class
type
/∗ Type of interest ∗/
SBs
value
sbsConf : SBs,
/∗ SB observers ∗/
∼
getSBSeg : [Link] × [Link] × SBs → [Link],
∼
getSBType : [Link] × SBs → [Link],
sbExistsInConf : [Link] × SBs → Bool,
/∗ Auxiliary functions ∗/
/∗ Invariants ∗/
is wf : SBs → Bool
is wf(sbs) ≡
sbsHaveConf(sbs) ∧
getSBSeg diff(sbs) ∧
getSBSeg point wf(sbs) ∧
getSBSeg injective(sbs) ∧
getSBSegType wf(sbs),
end
Segs
context: AA Types1
scheme AA Segs1(T : AA Types1) =
class
type
/∗ Type of interest ∗/
Segs
value
segsConf : Segs,
/∗ Segment observers ∗/
∼
getSegSB : [Link] × [Link] × Segs → [Link],
∼
getSegLength : [Link] × Segs → [Link],
∼
getSegMaxSpeed : [Link] × Segs → [Link],
segExistsInConf : [Link] × Segs → Bool,
/∗ Invariant ∗/
is wf : Segs → Bool
is wf(segs) ≡
segsHaveConf(segs) ∧
getSegSB injective(segs) ∧
brakeResPoint wf(segs),
/∗∗
∗ The SB in the end of a segment is different
∗ for two different segments or they are the
∗ same in both direction (being branches)
*∗/
getSegSB injective : Segs → Bool
getSegSB injective(segs) ≡
(
∀ seg1, seg2 : [Link],
dir : [Link] •
seg1 6= seg2 ⇒
(
getSegSB(seg1,dir,segs) 6= getSegSB(seg2,dir,segs)
)
∨
(
getSegSB(seg1,[Link],segs) = getSegSB(seg2,[Link],segs) ∧
getSegSB(seg1,[Link],segs) = getSegSB(seg2,[Link],segs)
)
),
end
ESAs
context: AA Types1
scheme AA ESAs1(T : AA Types1) =
class
type
/∗ Type of interest ∗/
ESAs
value
esasConf : ESAs,
/∗ ESA observers ∗/
∼
getESASB : [Link] × ESAs → [Link],
∼
getESALength : [Link] × ESAs → [Link],
esaExistsInConf : [Link] × ESAs → Bool,
/∗ Invariants ∗/
is wf : ESAs → Bool
is wf(esas) ≡
esasHaveConf(esas),
352 RSL modules
end
Trains
context: AA Types1
scheme AA Trains1(T : AA Types1) =
class
type
/∗ Type of interest ∗/
Trains
value
trainsConf : Trains,
/∗ Train observers ∗/
∼
getTrainLength : [Link] × Trains → [Link],
∼
getTrainMaxSpeed : [Link] × Trains → [Link],
∼
getTrainMaxAcc : [Link] × Trains → [Link],
∼
getTrainMaxDec : [Link] × Trains → [Link],
trainExistsInConf : [Link] × Trains → Bool,
/∗ Invariants ∗/
is wf : Trains → Bool
is wf(trains) ≡
trainsHaveConf(trains),
end
F.2.3 Dynamics
context: AA Statics1, AA TrainDyn1, AA SBDyn1, AA Types1
scheme AA Dynamics1(T : AA Types1, S : AA Statics1(T)) =
class
object
TD : AA TrainDyn1(T,S),
F.2 Decomposed model 353
SD : AA SBDyn1(T,S)
type
/∗ Type of interest ∗/
State = [Link] × [Link]
value
initState : State = ([Link], [Link]),
/∗ Point observer ∗/
∼
getPointPosition : [Link] × State × [Link] →
[Link]
getPointPosition(sb,(ts,sbs),con) ≡
[Link](sb,sbs,con)
pre [Link](sb,con) = [Link],
∼
getPointTicks : [Link] × State × [Link] → [Link]
getPointTicks(sb,(ts,sbs),con) ≡
[Link](sb,sbs,con)
pre [Link](sb,con) = [Link],
/∗ Point generator ∗/
setPointPosition : [Link] × [Link] × State ×
∼
[Link] → State
setPointPosition(sb,ppos,(ts,ss),con) ≡
(ts,[Link](sb,ppos,ss,con))
pre [Link](sb,con) = [Link] ∧
∼trainOnJunction(sb,con,(ts,ss)),
∼
setPointTicks : [Link] × [Link] × State × [Link] → State
setPointTicks(sb,ticks,(ts,ss),con) ≡
(ts,[Link](sb,ticks,ss,con))
pre [Link](sb,con) = [Link],
/∗ Crossing observer ∗/
∼
getBarrierPosition : [Link] × State × [Link] → [Link]
getBarrierPosition(sb,(ts,sbs),con) ≡
[Link](sb,sbs,con)
pre [Link](sb,con) = [Link],
∼
getSignalStatus : [Link] × State × [Link] → [Link]
getSignalStatus(sb,(ts,sbs),con) ≡
[Link](sb,sbs,con)
pre [Link](sb,con) = [Link],
/∗ Crossing generator ∗/
setBarrierPosition : [Link] × [Link] × State ×
∼
[Link] → State
setBarrierPosition(sb,bPos,(ts,sbs),con) ≡
(ts,[Link](sb,bPos,sbs,con))
pre [Link](sb,con) = [Link],
/∗ Sensor observer ∗/
getSensorStatus : [Link] × State → [Link]
getSensorStatus(sb,(ts,sbs)) ≡
[Link](sb,sbs),
/∗ Sensor generator ∗/
setSensorStatus : [Link] × [Link] × State ×
∼
[Link] → State
setSensorStatus(sb,senStat,(ts,ss),con) ≡
(ts,[Link](sb,senStat,ss))
pre sensor guard(sb,senStat,con,(ts,ss)),
/∗ Train observer ∗/
getTrainAcc : [Link] × State → [Link]
getTrainAcc(tID,(ts,sbs)) ≡
[Link](tID,ts),
/∗ Train generator ∗/
setTrainAcc : [Link] × [Link] × State ×
∼
[Link] → State
setTrainAcc(tID,acc,(ts,ss),con) ≡
([Link](tID,acc,ts,con),ss)
pre acc ≤ [Link](tID,con) ∧
[Link](tID,con) ≤ acc,
getTrainDirection(tID,(ts,ss)) = dir,
front = [Link](tp),
rear = [Link](tp),
tp = [Link] TrainPosition(rear,front),
s = setTrainDirection(t,dir,s)
in
setTrainPosition(t,tp,s,con)
end,
/∗ Processes ∗/
∼
tick : [Link] × [Link] × State → State
tick(tick,con,s) ≡
let
s = tickPoints(tick,con,s),
s = tickCrossings(tick,con,s),
s = tickTrains(tick,con,s)
in
s
end,
∼
tickPoints : [Link] × [Link] × State → State
tickPoints(tick,con,s) ≡
let
points = { p | p : [Link] • [Link](p,con) = [Link] }
in
pointProcess(points,tick,con,s)
end,
pp = getPointPosition(p,s,con)
in
case pp of
[Link] → s de setPointPosition(p,[Link],s,con),
[Link] → s de setPointPosition(p,[Link],s,con),
→s
end
end
pre [Link](p,con) = [Link],
∼
tickCrossings : [Link] × [Link] × State → State
tickCrossings(tick,con,s) ≡
let
crossings = { c | c : [Link] • [Link](c,con) = [Link] }
in
crossingProcess(crossings,tick,con,s)
end,
bp = setBarrierPosition(cr,[Link],s,con)
in
setSignalStatus(cr,[Link],s,con)
end
)
),
[Link] → s,
[Link] → s de setBarrierPosition(cr,[Link],s,con)
end
end
pre [Link](cr,con) = [Link],
∼
tickTrains : [Link] × [Link] × State → State
tickTrains(tick,con,s) ≡
let
trains = { t | t : [Link]}
in
trainProcess(trains,tick,con,s)
end,
∼
trainProcess : [Link]-set × [Link] × [Link] × State → State
trainProcess(trains,tick,con,s) ≡
if(trains = {})
then
s
else
let
t : [Link] • t ∈ trains,
trains = trains \ {t},
s = updateTrain(t,tick,con,s)
in
trainProcess(trains,tick,con,s)
end
end,
∼
updateTrain : [Link] × [Link] × [Link] × State → State,
/∗ Auxiliary functions ∗/
[Link] →
(
getBarrierPosition(sb,s,con) = [Link]
),
→ false
end
end
else
false
end,
case dir1 of
[Link] →
(
if (dir1 = dir2)
then
[Link]([Link](tp1),[Link](tp2),con) ⇒
∼[Link]([Link](tp1),[Link](tp2),con)
else
∼[Link]([Link](tp1),[Link](tp2),con)
end
),
362 RSL modules
[Link] →
(
if (dir1 = dir2) then
∼[Link]([Link](tp1),[Link](tp2),con) ⇒
[Link]([Link](tp1),[Link](tp2),con)
else
[Link]([Link](tp1),[Link](tp2),con)
end
)
end
),
/∗ Invariants etc. ∗/
/∗∗
∗ The position of a train may not overlap
∗ with the position of other trains
*∗/
noCollisions : [Link] × State → Bool
noCollisions(con,s) ≡
(
∀ t : [Link] •
∼trainPositionOccupied(t,getTrainPosition(t,s),s,con)
),
/∗∗
∗ Trains cannot end up on same segment
∗ driving in opposite directions away from each other.
∗
∗ If two train are on same segment driving in opposite
∗ directions then the train driving up must be lower
∗ on the line than the train driving down.
*∗/
trainPosPossible : [Link] × State → Bool
trainPosPossible(con,ds) ≡
(
∀ t1,t2 : [Link], segs : [Link]-set,
tp1,tp2 : [Link], seg : [Link] •
commonSegs(t1,t2,ds) 6= {} ∧
(tp1,tp2) = (getTrainPosition(t1,ds),getTrainPosition(t1,ds)) ∧
getTrainDirection(t1,ds) 6= getTrainDirection(t2,ds) ∧
getTrainDirection(t1,ds) = [Link]
⇒
[Link]([Link](tp1),[Link](tp2),con)
),
/∗∗
∗ If the train is located upon a junction,
F.2 Decomposed model 363
trainOnJunction(t,sb,con,ds) ∧
trainOnSegment(t,seg,con,ds) ∧
[Link](seg,con) ⇒
pointConnected(sb,seg,ds,con)
),
/∗ Wellformedness ∗/
is wf : State × [Link] → Bool
is wf((ts,ss),con) ≡
[Link] wf(ts,con) ∧
[Link] wf(ss,con),
axiom
[ wellformedness ]
init req(initState,[Link]),
[ gen wf setPointPosition ]
∀ p : [Link], pp : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](p,con) = [Link] ∧
∼trainOnJunction(p,con,s)
⇒
is wf(setPointPosition(p,pp,s,con),con),
364 RSL modules
[ gen wf setPointTicks ]
∀ p : [Link], ticks : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](p,con) = [Link]
⇒
is wf(setPointTicks(p,ticks,s,con),con),
[ gen wf setBarrierPosition ]
∀ cr : [Link], bp : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](cr,con) = [Link]
⇒
is wf(setBarrierPosition(cr,bp,s,con),con),
[ gen wf setSignalStatus ]
∀ cr : [Link], ss : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
[Link](cr,con) = [Link]
⇒
is wf(setSignalStatus(cr,ss,s,con),con),
[ gen wf setSensorStatus ]
∀ sen : [Link], ss : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
sensor guard(sen,ss,con,s)
⇒
is wf(setSensorStatus(sen,ss,s,con),con),
[ gen wf setTrainAcc ]
∀ t : [Link], acc : [Link],
con : [Link], s : State •
is wf(s,con) ∧
acc ≤ [Link](t,con) ∧
[Link](t,con) ≤ acc
⇒
is wf(setTrainAcc(t,acc,s,con),con),
[ gen wf setTrainSpeed ]
∀ t : [Link], sp : [Link],
con : [Link], s : State •
is wf(s,con) ∧
sp ≤ [Link](t,con)
⇒
is wf(setTrainSpeed(t,sp,s,con),con),
[ gen wf setTrainPosition ]
∀ t : [Link], pos : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
∼trainPositionOccupied(t,pos,s,con)
⇒
is wf(setTrainPosition(t,pos,s,con),con),
F.2 Decomposed model 365
[ gen wf setTrainDirection ]
∀ t : [Link], dir : [Link], s : State,
con : [Link] •
is wf(s,con) ∧
(
getTrainSpeed(t,s) = 0.0 ∨
getTrainDirection(t,s) = dir
)
⇒
is wf(setTrainDirection(t,dir,s),con)
end
TrainDyn
value
initTrainStates : TrainStates,
/∗ Train observer ∗/
∼
getTrainAcc : [Link] × TrainStates → [Link],
∼
getTrainSpeed : [Link] × TrainStates → [Link],
∼
getTrainPosition : [Link] × TrainStates→[Link],
∼
getTrainDirection : [Link] × TrainStates → [Link],
/∗ Train generator ∗/
setTrainAcc : [Link] × [Link] × TrainStates ×
∼
[Link] → TrainStates,
setTrainSpeed : [Link] × [Link] × TrainStates ×
∼
[Link] → TrainStates,
setTrainPosition : [Link] × [Link] ×
∼
TrainStates × [Link] →
TrainStates,
setTrainDirection : [Link] × [Link] ×
∼
TrainStates → TrainStates,
[Link](t,con)) ∧
train pos dir ok(getTrainDirection(t,s),tp,s,con)
end
),
[Link] →
(
[Link]([Link](tp),[Link](tp),con)
)
end
),
∼
getTrainSegments : [Link] × TrainStates →
[Link]-set
getTrainSegments(t,s) ≡
[Link](getTrainPosition(t,s)),
∼
trainInESA : [Link] × TrainStates → Bool
trainInESA(t,s) ≡
[Link](getTrainPosition(t,s)),
trainFrontLoc(t,ds) ≡
case [Link](getTrainPosition(t,ds)) of
[Link]( ) → [Link](getTrainPosition(t,ds)),
[Link](seg) → [Link](seg)
end,
∼
is wf : TrainStates × [Link] → Bool
is wf(s,con) ≡
allTrainStatesExist(s) ∧
train pos wf(con,s),
axiom
/∗∗
∗ Observer generator axioms
*∗/
/∗ getTrainAcc gen ∗/
[ getTrainAcc setTrainAcc ]
∀ s : TrainStates, t1,t2 : [Link],
acc : [Link],
con : [Link] •
getTrainAcc(t1,setTrainAcc(t2,acc,s,con)) ≡
if(t1 = t2)
then
acc
else
getTrainAcc(t1,s)
end
pre acc ≤ [Link](t2,con) ∧
[Link](t2,con) ≤ acc ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainAcc setTrainSpeed ]
∀ s : TrainStates, t1,t2 : [Link], sp : [Link],
con : [Link] •
getTrainAcc(t1,setTrainSpeed(t2,sp,s,con)) ≡
getTrainAcc(t1,s)
pre sp ≤ [Link](t2,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainAcc setTrainPosition ]
∀ s : TrainStates, t1,t2 : [Link], tp : [Link],
con : [Link] •
getTrainAcc(t1,setTrainPosition(t2,tp,s,con)) ≡
getTrainAcc(t1,s)
pre train pos ok(t2,tp,s,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainAcc setTrainDirection ]
∀ s : TrainStates, t1,t2 : [Link], dir : [Link]•
getTrainAcc(t1,setTrainDirection(t2,dir,s)) ≡
getTrainAcc(t1,s)
pre (getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
/∗ getTrainSpeed gen ∗/
[ getTrainSpeed setTrainAcc ]
∀ s : TrainStates, t1,t2 : [Link], acc : [Link],
F.2 Decomposed model 369
con : [Link] •
getTrainSpeed(t1,setTrainAcc(t2,acc,s,con)) ≡
getTrainSpeed(t1,s)
pre acc ≤ [Link](t2,con) ∧
[Link](t2,con) ≤ acc ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainSpeed setTrainSpeed ]
∀ s : TrainStates, t1,t2 : [Link], sp : [Link],
con : [Link] •
getTrainSpeed(t1,setTrainSpeed(t2,sp,s,con)) ≡
if(t1 = t2)
then
sp
else
getTrainSpeed(t1,s)
end
pre sp ≤ [Link](t2,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainSpeed setTrainPosition ]
∀ s : TrainStates, t1,t2 : [Link], tp : [Link],
con : [Link] •
getTrainSpeed(t1,setTrainPosition(t2,tp,s,con)) ≡
getTrainSpeed(t1,s)
pre train pos ok(t2,tp,s,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainSpeed setTrainDirection ]
∀ s : TrainStates, t1,t2 : [Link], dir : [Link]•
getTrainSpeed(t1,setTrainDirection(t2,dir,s)) ≡
getTrainSpeed(t1,s)
pre (getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
/∗ getTrainPosition gen ∗/
[ getTrainPosition setTrainAcc ]
∀ s : TrainStates, t1,t2 : [Link], acc : [Link],
con : [Link] •
getTrainPosition(t1,setTrainAcc(t2,acc,s,con)) ≡
getTrainPosition(t1,s)
pre acc ≤ [Link](t2,con) ∧
[Link](t2,con) ≤ acc ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainPosition setTrainSpeed ]
∀ s : TrainStates, t1,t2 : [Link], sp : [Link],
con : [Link] •
getTrainPosition(t1,setTrainSpeed(t2,sp,s,con)) ≡
getTrainPosition(t1,s)
370 RSL modules
pre sp ≤ [Link](t2,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainPosition setTrainPosition ]
∀ s : TrainStates, t1,t2 : [Link], tp : [Link],
con : [Link] •
getTrainPosition(t1,setTrainPosition(t2,tp,s,con)) ≡
if(t1 = t2)
then
tp
else
getTrainPosition(t1,s)
end
pre train pos ok(t2,tp,s,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainPosition setTrainDirection ]
∀ s : TrainStates, t1,t2 : [Link], dir : [Link]•
getTrainPosition(t1,setTrainDirection(t2,dir,s)) ≡
getTrainPosition(t1,s)
pre (getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
/∗ getTrainDirection gen ∗/
[ getTrainDirection setTrainAcc ]
∀ s : TrainStates, t1,t2 : [Link], acc : [Link],
con : [Link] •
getTrainDirection(t1,setTrainAcc(t2,acc,s,con)) ≡
getTrainDirection(t1,s)
pre acc ≤ [Link](t2,con) ∧
[Link](t2,con) ≤ acc ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainDirection setTrainSpeed ]
∀ s : TrainStates, t1,t2 : [Link], sp : [Link],
con : [Link] •
getTrainDirection(t1,setTrainSpeed(t2,sp,s,con)) ≡
getTrainDirection(t1,s)
pre sp ≤ [Link](t2,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
[ getTrainDirection setTrainPosition ]
∀ s : TrainStates, t1,t2 : [Link], tp : [Link],
con : [Link] •
getTrainDirection(t1,setTrainPosition(t2,tp,s,con)) ≡
getTrainDirection(t1,s)
pre train pos ok(t2,tp,s,con) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s),
F.2 Decomposed model 371
[ getTrainDirection setTrainDirection ]
∀ s : TrainStates, t1,t2 : [Link], dir : [Link]•
getTrainDirection(t1,setTrainDirection(t2,dir,s)) ≡
if(t1 = t2)
then
dir
else
getTrainDirection(t1,s)
end
pre (getTrainSpeed(t2,s) = 0.0 ∨
getTrainDirection(t2,s) = dir) ∧
trainStateExists(t1,s) ∧
trainStateExists(t2,s)
end
SBDyn
value
initSBStates : SBStates,
/∗ Point observer ∗/
getPointPosition : [Link] × SBStates ×
∼
[Link] → [Link],
getPointTicks : [Link] × SBStates ×
∼
[Link] → [Link],
/∗ Point generator ∗/
setPointPosition : [Link] × [Link] × SBStates ×
∼
[Link] → SBStates,
setPointTicks : [Link] × [Link] × SBStates ×
∼
[Link] → SBStates,
/∗ Crossing observer ∗/
getBarrierPosition : [Link] × SBStates ×
∼
[Link] → [Link],
getSignalStatus : [Link] × SBStates ×
∼
[Link] → [Link],
/∗ Crossing generator ∗/
setBarrierPosition : [Link] × [Link] × SBStates ×
∼
[Link] → SBStates,
setSignalStatus : [Link] × [Link] × SBStates ×
∼
[Link] → SBStates,
/∗ Sensor observer ∗/
getSensorStatus : [Link] × SBStates → [Link],
372 RSL modules
/∗ Sensor generator ∗/
setSensorStatus : [Link] × [Link] ×
SBStates → SBStates,
getBarrierPosition(sb,s,con) = [Link]
),
axiom
/∗∗
∗ Observer generator axioms
∗ Only the relevant axioms are shown
∗ All other observer generator pairs are by definition
∗ unaffected by each other
*∗/
/∗ getPointPosition ∗/
[ getPointPosition setPointPosition ]
∀ sb1,sb2 : [Link], pp : [Link],
s : SBStates,
con : [Link] •
getPointPosition(sb1,setPointPosition(sb2,pp,s,con),con) ≡
if(sb1 = sb2)
then
pp
else
getPointPosition(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getPointPosition setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : SBStates,
con : [Link] •
getPointPosition(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getPointPosition setBarrierPosition ]
∀ sb1,sb2 : [Link], bp : [Link],
s : SBStates,
con : [Link] •
getPointPosition(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
374 RSL modules
crossingStateExists(sb2,s,con),
[ getPointPosition setSignalStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : SBStates,
con : [Link] •
getPointPosition(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getPointPosition setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : SBStates,
con : [Link] •
getPointPosition(sb1,setSensorStatus(sb2,ss,s),con) ≡
getPointPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
/∗ getPointTicks gen∗/
[ getPointTicks setPointPosition ]
∀ sb1,sb2 : [Link], pp : [Link],
s : SBStates,
con : [Link] •
getPointTicks(sb1,setPointPosition(sb2,pp,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getPointTicks setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : SBStates,
con : [Link] •
getPointTicks(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
if(sb1 = sb2)
then
ticks
else
getPointTicks(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getPointTicks setBarrierPosition ]
∀ sb1,sb2 : [Link], bp : [Link],
s : SBStates,
con : [Link] •
getPointTicks(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
F.2 Decomposed model 375
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getPointTicks setSignalStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : SBStates,
con : [Link] •
getPointTicks(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getPointTicks setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : SBStates,
con : [Link] •
getPointTicks(sb1,setSensorStatus(sb2,ss,s),con) ≡
getPointTicks(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
pointStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
/∗ getBarrierPosition gen ∗/
[ getBarrierPosition setPointPosition ]
∀ sb1, sb2 : [Link], pp : [Link],
s : SBStates,
con : [Link] •
getBarrierPosition(sb1,setPointPosition(sb2,pp,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getBarrierPosition setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : SBStates,
con : [Link] •
getBarrierPosition(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getBarrierPosition setBarrierPosition ]
∀ s : SBStates, sb1,sb2 : [Link], bp : [Link],
con : [Link] •
getBarrierPosition(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
if(sb1 = sb2)
then
376 RSL modules
bp
else
getBarrierPosition(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getBarrierPosition setSignalStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : SBStates,
con : [Link] •
getBarrierPosition(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getBarrierPosition setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : SBStates,
con : [Link] •
getBarrierPosition(sb1,setSensorStatus(sb2,ss,s),con) ≡
getBarrierPosition(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
/∗ getSignalStatus gen ∗/
[ getSignalStatus setPointPosition ]
∀ sb1, sb2 : [Link], pp : [Link],
s : SBStates,
con : [Link] •
getSignalStatus(sb1,setPointPosition(sb2,pp,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getSignalStatus setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : SBStates,
con : [Link] •
getSignalStatus(sb1,setPointTicks(sb2,ticks,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
pointStateExists(sb2,s,con),
[ getSignalStatus setBarrierPosition ]
∀ s : SBStates, sb1,sb2 : [Link], bp : [Link],
con : [Link] •
F.2 Decomposed model 377
getSignalStatus(sb1,setBarrierPosition(sb2,bp,s,con),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getSignalStatus setSignalStatus ]
∀ s : SBStates, sb1,sb2 : [Link], ss : [Link],
con : [Link] •
getSignalStatus(sb1,setSignalStatus(sb2,ss,s,con),con) ≡
if(sb1 = sb2)
then
ss
else
getSignalStatus(sb1,s,con)
end
pre [Link](sb1,con) = [Link] ∧
[Link](sb2,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
crossingStateExists(sb2,s,con),
[ getSignalStatus setSensorStatus ]
∀ sb1,sb2 : [Link], ss : [Link],
s : SBStates,
con : [Link] •
getSignalStatus(sb1,setSensorStatus(sb2,ss,s),con) ≡
getSignalStatus(sb1,s,con)
pre [Link](sb1,con) = [Link] ∧
crossingStateExists(sb1,s,con) ∧
sensorStateExists(sb2,s),
/∗ getSensorStatus gen ∗/
[ getSensorStatus setPointPosition ]
∀ sb1, sb2 : [Link], pp : [Link],
s : SBStates,
con : [Link] •
getSensorStatus(sb1,setPointPosition(sb2,pp,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
pointStateExists(sb2,s,con),
[ getSensorStatus setPointTicks ]
∀ sb1,sb2 : [Link], ticks : [Link],
s : SBStates,
con : [Link] •
getSensorStatus(sb1,setPointTicks(sb2,ticks,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
pointStateExists(sb2,s,con),
[ getSensorStatus setBarrierPosition ]
∀ s : SBStates, sb1,sb2 : [Link], bp : [Link],
con : [Link] •
378 RSL modules
getSensorStatus(sb1,setBarrierPosition(sb2,bp,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
crossingStateExists(sb2,s,con),
[ getSensorStatus setSignalStatus ]
∀ s : SBStates, sb1,sb2 : [Link], ss : [Link],
con : [Link] •
getSensorStatus(sb1,setSignalStatus(sb2,ss,s,con)) ≡
getSensorStatus(sb1,s)
pre [Link](sb2,con) = [Link] ∧
sensorStateExists(sb1,s) ∧
crossingStateExists(sb2,s,con),
[ getSensorStatus setSensorStatus ]
∀ s : SBStates, sb1,sb2 : [Link], ss : [Link],
con : [Link] •
getSensorStatus(sb1,setSensorStatus(sb2,ss,s)) ≡
if(sb1 = sb2)
then
ss
else
getSensorStatus(sb1,s)
end
pre sensorStateExists(sb1,s) ∧
sensorStateExists(sb2,s)
end
F.2.4 Control
context: AA Dynamics1, AA ComService1, AA SBCC1, AA TCC1
scheme AA Control1(T : AA Types1, S : AA Statics1(T),
D : AA Dynamics1(T,S)) =
class
object
COM : AA ComService1(T),
SBCC : AA SBCC1(T,S,D,COM),
TCC : AA TCC1(T,S,D,COM)
type
ControlState = SBCCStates × TCCStates,
SBCCStates = [Link] →
m [Link],
TCCStates = [Link] →
m [Link]
value
initControlState : ControlState,
∼
getSBCCState : [Link] × ControlState → [Link]
getSBCCState(sb,(sbccs,tccs)) ≡
sbccs(sb)
pre sbccStateExists(sb,(sbccs,tccs)),
/∗ Processes ∗/
tick : [Link] × ControlState × [Link] ×
∼
[Link] → out [Link]
(ControlState × [Link])
tick(tick,cs,ds,con) ≡
(
let
tSet = {t | t : [Link]},
sbSet = {sb | sb : [Link]},
(cs,ds) = tickTCCs(tSet,tick,cs,ds,con),
cs = tickSBCCs(sbSet,tick,cs,ds,con)
in
(cs,ds)
end
),
end
end,
/∗ Communication ∗/
∼
comService : ControlState → in [Link] ControlState
comService(cs) ≡
let
comMsg = [Link]()
in
case [Link](comMsg) of
[Link](sb) →
(
let
sbcc = getSBCCState(sb,cs),
sbcc = [Link](comMsg, sbcc)
in
updateSBCCState(sb,sbcc,cs)
end
),
[Link](t) →
(
let
tcc = getTCCState(t,cs),
tcc = [Link](comMsg,tcc)
in
updateTCCState(t,tcc,cs)
end
)
end
end,
/∗ Invariants ∗/
is wf : ControlState × [Link] × [Link] → Bool
is wf(cs,ds,con) ≡
[Link] wf(ds,con) ∧
tcc has state(cs) ∧
sbcc has state(cs),
/∗∗
∗ Defines that the control system and all its
∗ components must be consistent e.g. the information
∗ stored in the control system must reflect the
∗ physical world and unintended states must not occur.
∗ Also the physical world must abide by the rules
∗ of the control system.
*∗/
consistent : ControlState × [Link] × [Link] → Bool
consistent(cs,ds,con) ≡
is wf(cs,ds,con) ∧
train on branch dir(ds,con) ∧
tcc hasRes passedResPoint(cs,ds,con) ∧
sbcc res wf(cs,con) ∧
position branch sbcc res wf(cs,ds,con) ∧
tcc res branch wf(cs,ds,con) ∧
position sl sbcc res wf(cs,ds,con),
guard1,guard2 : [Link],
sbcc1,sbcc2 : [Link],
res : [Link] •
[Link](t,seg,con,ds) ∧
[Link](t,con,ds) ∧
[Link](getTCCState(t,cs)) ∧
trainDir = [Link](t,ds) ∧
guard1 = [Link](seg,[Link](trainDir),con) ∧
guard2 = [Link](guard1,trainDir,con) ∧
sbcc1 = getSBCCState(guard1,cs) ∧
sbcc2 = getSBCCState(guard2,cs) ∧
res = [Link] res(t,trainDir)
⇒
[Link](res) = [Link](sbcc1) ∧
[Link](res) = [Link](sbcc2) ∧
[Link](res) = [Link](sbcc2)
),
tcc = getTCCState(t,cs) ⇒
[Link](tcc)
),
sbcc = getSBCCState(sb,cs) ⇒
[Link](sbcc)
)
axiom
/∗ The initial state has to be wellformed and fullfill the
initial state requirements ∗/
[ initial state ]
initReq(initControlState,[Link],[Link]),
/∗ SBCC gen wf ∗/
[ gen wf setSBCCLineRes ]
∀ con : [Link],
ds : [Link],
res : [Link],
sb : [Link],
sbcc : [Link],
cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) ∈ {[Link], [Link]} ∧
sbcc = getSBCCState(sb,cs)
⇒
is wf(updateSBCCState(sb,
[Link](res,sbcc),cs),ds,con),
[ gen wf setSBCCBranchRes ]
∀ con : [Link],
ds : [Link],
sb : [Link],
F.2 Decomposed model 385
sbcc : [Link],
res : [Link], cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) = [Link] ∧
sbcc = getSBCCState(sb,cs)
⇒
is wf(updateSBCCState(sb,
[Link](res,sbcc),cs),ds,con),
[ gen wf removeSBCCLineRes ]
∀ con : [Link],
sb : [Link],
sbcc : [Link],
ds : [Link], cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) ∈ {[Link], [Link]} ∧
sbcc = getSBCCState(sb,cs)
⇒
is wf(updateSBCCState(sb,
[Link](sbcc),cs),ds,con),
[ gen wf removeSBCCBranchRes ]
∀ con : [Link],
sb : [Link],
sbcc : [Link],
ds : [Link], cs : ControlState •
is wf(cs,ds,con) ∧
[Link](sb,con) = [Link] ∧
sbcc = getSBCCState(sb,cs)
⇒
is wf(updateSBCCState(sb,
[Link](sbcc),cs),ds,con),
[ gen wf setLastSensorStatus ]
∀ con : [Link],
sb : [Link],
sbcc : [Link],
ds : [Link], cs : ControlState,
ss : [Link] •
is wf(cs,ds,con) ∧
sbcc = getSBCCState(sb,cs)
⇒
is wf(updateSBCCState(sb,
[Link](ss,sbcc),cs),ds,con),
[ gen wf storeSBCCMsg ]
∀ con : [Link],
sb : [Link],
sbcc : [Link],
ds : [Link], cs : ControlState,
cm : [Link] •
is wf(cs,ds,con) ∧
sbcc = getSBCCState(sb,cs)
⇒
is wf(updateSBCCState(sb,
[Link](cm,sbcc),cs),ds,con),
386 RSL modules
[ gen wf setSBCCPrepRes ]
∀ con : [Link],
sb : [Link],
sbcc : [Link],
ds : [Link], cs : ControlState,
hr : [Link] •
is wf(cs,ds,con) ∧
sbcc = getSBCCState(sb,cs)
⇒
is wf(updateSBCCState(sb,
[Link](hr,sbcc),cs),ds,con),
/∗ TCC gen wf ∗/
[ gen wf setTCCRes ]
∀ con : [Link],
cs : ControlState,
t : [Link],
ds : [Link],
tcc : [Link],
b : Bool •
is wf(cs,ds,con) ∧
tcc = getTCCState(t,cs)
⇒
is wf(updateTCCState(t,
[Link](b,tcc),cs),ds,con),
[ gen wf setTCCRequesting ]
∀ con : [Link],
ds : [Link],
tcc : [Link],
cs : ControlState,
t : [Link],
b : Bool •
is wf(cs,ds,con) ∧
tcc = getTCCState(t,cs)
⇒
is wf(updateTCCState(t,
[Link](b,tcc),cs),ds,con),
[ gen wf setTrainDecelerating ]
∀ con : [Link],
ds : [Link],
cs : ControlState,
tcc : [Link],
t : [Link],
b : Bool •
is wf(cs,ds,con) ∧
tcc = getTCCState(t,cs)
⇒
is wf(updateTCCState(t,
[Link](b,tcc),cs),ds,con)
end
F.2 Decomposed model 387
TCC
value
initTCCState : TCCState,
/∗ Processes ∗/
tccMsgReceiver : [Link] × TCCState → TCCState
tccMsgReceiver(comMsg,tcc) ≡
let
resp = [Link](comMsg)
in
case resp of
[Link](resGranted) →
(
let
tcc = setTCCRequesting(false,tcc)
in
if(resGranted)
then
setTCCRes(true,tcc)
else
tcc
end
end
),
→ tcc
end
end,
(cs,ds) = handleRes(t,cs,ds,con)
in
(cs,ds)
end,
frontSeg = [Link](isSeg),
segMaxSpeed = [Link](frontSeg,con)
in
if (ts > segMaxSpeed ∨ ts > trainMaxSpeed)
then
decelerateTrain(t,cs,ds,con)
else
checkDeceleration(t,cs,ds,con)
end
end
end
end, /∗ let ∗/
end,
[Link](seg) →
(
(sendTCCReq(t,[Link](seg,dir,con),dir,cs),ds)
)
end /∗ case ∗/
end, /∗ let ∗/
/∗ Invariants ∗/
initReq : TCCState → Bool
initReq(tcc) ≡
no tcc res(tcc) ∧
tcc not requesting(tcc) ∧
tcc not decelerating(tcc),
axiom
/∗ obs gen ∗/
/∗ hasTCCRes gen ∗/
[ hasTCCRes setTCCRes ]
∀ b : Bool, tcc : TCCState •
hasTCCRes(setTCCRes(b,tcc)) ≡
b,
[ hasTCCRes setTCCRequesting ]
∀ b : Bool, tcc : TCCState •
hasTCCRes(setTCCRequesting(b,tcc)) ≡
hasTCCRes(tcc),
[ hasTCCRes setTrainDecelerating ]
∀ b : Bool, tcc : TCCState •
hasTCCRes(setTrainDecelerating(b,tcc)) ≡
hasTCCRes(tcc),
/∗ isTCCRequesting gen ∗/
[ isTCCRequesting setTCCRes ]
∀ b : Bool, tcc : TCCState •
isTCCRequesting(setTCCRes(b,tcc)) ≡
isTCCRequesting(tcc),
[ isTCCRequesting setTCCRequesting ]
∀ b : Bool, tcc : TCCState •
isTCCRequesting(setTCCRequesting(b,tcc)) ≡
b,
[ isTCCRequesting setTrainDecelerating ]
∀ b : Bool, tcc : TCCState •
isTCCRequesting(setTrainDecelerating(b,tcc)) ≡
isTCCRequesting(tcc),
/∗ isTrainDecelerating gen ∗/
[ isTrainDecelerating setTCCRes ]
∀ b : Bool, tcc : TCCState •
392 RSL modules
isTrainDecelerating(setTCCRes(b,tcc)) ≡
isTrainDecelerating(tcc),
[ isTrainDecelerating setTCCRequesting ]
∀ b : Bool, tcc : TCCState •
isTrainDecelerating(setTCCRequesting(b,tcc)) ≡
isTrainDecelerating(tcc),
[ isTrainDecelerating setTrainDecelerating ]
∀ b : Bool, tcc : TCCState •
isTrainDecelerating(setTrainDecelerating(b,tcc)) ≡
b
end
SBCC
value
initSBCCState : SBCCState,
isPreparing(cs) ≡
case getPrepRes(cs) of
[Link] → false,
→ true
end,
/∗ Processes ∗/
sbccProcess : [Link] × [Link] × SBCCState × [Link] ×
[Link] →
out [Link] SBCCState
sbccProcess(sb,tick,cs,ds,con) ≡
let
cs = sensorProcess(sb,cs,ds,con)
in
if(isPreparing(cs))
then
prepareProcess(sb,cs,ds,con)
else
sbccMsgProcess(sb,cs,ds,con)
end
end,
train = [Link](res),
cs = removePrepRes(cs)
in
sendSBCCMsg(sb,[Link](train),[Link](true));cs
end
else
cs
end
),
→ cs
end,
→ (cs,ds)
end
end,
[Link] × [Link] →
SBCCState × [Link]
prepareSeg(sb,res,cs,ds,con) ≡
let
cs = setPrepRes([Link](res),cs)
in
case [Link](sb,con) of
[Link] →
(
let
ds = [Link](sb,[Link],ds,con)
in
(cs,ds)
end
),
[Link] →
(
case [Link](res) of
[Link] →
(
let
ds = [Link](sb,[Link],ds,con)
in
(cs,ds)
end
),
[Link] →
(
let
ds = [Link](sb,[Link],ds,con)
in
(cs,ds)
end
)
end
),
→ (cs,ds)
end
end,
sbcc = removeLineRes(sbcc)
in
sendLDeResMsg(sb,[Link](sb,con));sbcc
end
else
sbcc
end /∗ if ∗/
end /∗ let ∗/
),
[Link] →
(
let
[Link](lineRes) = getLineRes(sbcc),
pointDir = [Link](sb,con)
in
if([Link](lineRes) = pointDir)
then
let
sbcc = removeLineRes(sbcc)
in
sendLDeResMsg(sb,[Link](sb,con)); sbcc
end
else
sendBDeResMsg(sb,[Link](sb,con)); sbcc
end /∗ if ∗/
end /∗ let ∗/
)
end /∗ case ∗/
pre [Link](sb,con),
let
(hasComMsg,sbcc) = getNextMsg(sbcc)
in
case hasComMsg of
[Link]([Link] comMsg(sender,receiver,msg)) →
(
case sender of
[Link]( ) →
(
let
(retMsg,sbcc,ds) =
handleTCCMsg(sb,msg,sbcc,ds,con)
in
case retMsg of
[Link](aMsg) →
sendSBCCMsg(sb,sender,aMsg); sbcc,
→ sbcc
end
end
),
[Link]( ) →
(
let
(sbcc,retMsg) = handleSBCCMsg(sb,msg,sbcc)
in
case retMsg of
[Link](aMsg) →
sendSBCCMsg(sb,sender,aMsg); sbcc,
→ sbcc
end
end
)
end /∗ case ∗/
),
→ sbcc /∗ no message to process ∗/
end
end, /∗ let ∗/
/∗ Response ∗/
[Link]( ) → handleLBResp(sb,msg,sbcc),
/∗ De reservation ∗/
[Link] → handleDeResMsg(msg,sbcc),
[Link] → handleDeResMsg(msg,sbcc),
[Link] → handleDeResMsg(msg,sbcc)
end,
[Link] × [Link] →
out [Link] [Link] ×
SBCCState × [Link]
handleTCCMsg(sb,msg,cs,ds,con) ≡
let
[Link](res) = msg
in
case [Link](sb,con) of
[Link] →
(
/∗ if direction away from end → send msg
else OK
∗/
if([Link](res) = [Link](sb,con))
then
let
(cs,ds) = prepareSeg(sb,res,cs,ds,con)
in
([Link],cs,ds)
end
else
if(lineFree(cs))
then
let
cs = setLineRes([Link](res),cs),
cs = sendLBResMsg(sb,
[Link](sb,con),res)
in
([Link],cs,ds)
end
else
([Link]([Link](false)),cs,ds)
end
end
),
end
else
([Link]([Link](false)),cs,ds)
end
end
),
→ /∗ PLAINSB, CROSSINGSB ∗/
(
let
(cs,ds) = prepareSeg(sb,res,cs,ds,con)
in
([Link],cs,ds)
end
)
end /∗ case ∗/
end, /∗ let ∗/
out [Link]
SBCCState × [Link]
handleLBResp(sb,msg,sbcc) ≡
let
[Link](res,granted) = msg
in
if(granted)
then
sendSBCCMsg(sb,[Link]([Link](res)),
[Link](true));
(sbcc,[Link])
else
let
sbcc = removeLineRes(sbcc)
in
sendSBCCMsg(sb,[Link]([Link](res)),
[Link](false));
(sbcc,[Link])
end
end
end,
/∗ case(msg)
lb → deres line; deres branch
l → deres line;
b → deres branch;
∗/
handleDeResMsg : [Link] × SBCCState →
SBCCState × [Link]
handleDeResMsg(msg,sbcc) ≡
case msg of
[Link] →
(
let
sbcc = removeLineRes(sbcc),
sbcc = removeBranchRes(sbcc)
in
(sbcc,[Link])
end
),
[Link] →
(
let
sbcc = removeLineRes(sbcc)
in
(sbcc,[Link])
end
),
[Link] →
(
let
sbcc = removeBranchRes(sbcc)
in
(sbcc,[Link])
end
F.2 Decomposed model 401
)
end,
/∗ Invariants ∗/
initReq : SBCCState → Bool
initReq(sbcc) ≡
no sbcc res(sbcc) ∧
sbcc not preparing(sbcc),
axiom
/∗ getSBCCLineRes gen∗/
[ getSBCCLineRes setLineRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getLineRes(setLineRes([Link](sbRes),sbcc)) ≡
[Link](sbRes),
[ getLineRes setBranchRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getLineRes(setBranchRes([Link](sbRes),sbcc)) ≡
getLineRes(sbcc),
[ getLineRes setLastSensorStatus ]
∀ ss : [Link], sbcc : SBCCState •
getLineRes(setLastSensorStatus(ss,sbcc)) ≡
getLineRes(sbcc),
[ getLineRes storeMsg ]
∀ cm : [Link], sbcc : SBCCState •
getLineRes(storeMsg(cm,sbcc)) ≡
getLineRes(sbcc),
[ getLineRes setPrepRes ]
∀ hr : [Link], sbcc : SBCCState •
getLineRes(setPrepRes(hr,sbcc)) ≡
getLineRes(sbcc),
/∗ getSBCCBranchRes gen ∗/
402 RSL modules
[ getBranchRes setLineRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getBranchRes(setLineRes([Link](sbRes),sbcc)) ≡
getBranchRes(sbcc),
[ getBranchRes setBranchRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getBranchRes(setBranchRes([Link](sbRes),sbcc)) ≡
[Link](sbRes),
[ getBranchRes setLastSensorStatus ]
∀ ss : [Link], sbcc : SBCCState •
getBranchRes(setLastSensorStatus(ss,sbcc)) ≡
getBranchRes(sbcc),
[ getBranchRes storeMsg ]
∀ cm : [Link], sbcc : SBCCState •
getBranchRes(storeMsg(cm,sbcc)) ≡
getBranchRes(sbcc),
[ getBranchRes setPrepRes ]
∀ hr : [Link], sbcc : SBCCState •
getBranchRes(setPrepRes(hr,sbcc)) ≡
getBranchRes(sbcc),
/∗ getLastSensorStatus gen ∗/
[ getLastSensorStatus setLineRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getLastSensorStatus(setLineRes([Link](sbRes),sbcc)) ≡
getLastSensorStatus(sbcc),
[ getLastSensorStatus setBranchRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getLastSensorStatus(setBranchRes([Link](sbRes),sbcc)) ≡
getLastSensorStatus(sbcc),
[ getLastSensorStatus setLastSensorStatus ]
∀ ss : [Link], sbcc : SBCCState •
getLastSensorStatus(setLastSensorStatus(ss,sbcc)) ≡
ss,
[ getLastSensorStatus storeMsg ]
∀ cm : [Link], sbcc : SBCCState •
getLastSensorStatus(storeMsg(cm,sbcc)) ≡
getLastSensorStatus(sbcc),
[ getLastSensorStatus setPrepRes ]
∀ hr : [Link], sbcc : SBCCState •
getLastSensorStatus(setPrepRes(hr,sbcc)) ≡
getLastSensorStatus(sbcc),
/∗ getNextMsg gen ∗/
[ getNextMsg setLineRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getNextMsg(setLineRes([Link](sbRes),sbcc)) ≡
F.3 Concrete model 403
getNextMsg(sbcc),
[ getNextMsg setBranchRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getNextMsg(setBranchRes([Link](sbRes),sbcc)) ≡
getNextMsg(sbcc),
[ getNextMsg setLastSensorStatus ]
∀ ss : [Link], sbcc : SBCCState •
getNextMsg(setLastSensorStatus(ss,sbcc)) ≡
getNextMsg(sbcc),
[ getNextMsg setPrepRes ]
∀ hr : [Link], sbcc : SBCCState •
getNextMsg(setPrepRes(hr,sbcc)) ≡
getNextMsg(sbcc),
/∗ getPrepRes gen ∗/
[ getPrepRes setLineRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getPrepRes(setLineRes([Link](sbRes),sbcc)) ≡
getPrepRes(sbcc),
[ getPrepRes setBranchRes ]
∀ sbcc : SBCCState, sbRes : [Link] •
getPrepRes(setBranchRes([Link](sbRes),sbcc)) ≡
getPrepRes(sbcc),
[ getPrepRes setLastSensorStatus ]
∀ ss : [Link], sbcc : SBCCState •
getPrepRes(setLastSensorStatus(ss,sbcc)) ≡
getPrepRes(sbcc),
[ getPrepRes storeMsg ]
∀ cm : [Link], sbcc : SBCCState •
getPrepRes(storeMsg(cm,sbcc)) ≡
getPrepRes(sbcc),
[ getPrepRes setPrepRes ]
∀ hr : [Link], sbcc : SBCCState •
getPrepRes(setPrepRes(hr,sbcc)) ≡
hr
end
ID = Text,
ESAID = End,
SBID = {| sb : ID • sbIDLimit(sb) |},
SegmentID = {| seg : ID • segIDLimit(seg) |},
TrainID = {| t : ID • trainIDLimit(t) |},
/∗ Physical parameters ∗/
Length = Real,
Speed = Real,
Acceleration = Real,
/∗ Neighbour of a SB in a direction ∗/
SBSegment ==
seg(getSeg : SegmentID) |
point(getUpSeg : SegmentID, getDownSeg : SegmentID) |
esa(getESA : ESAID),
/∗ The type of a SB ∗/
SBType == POINTSB | ENDSB | CROSSINGSB | PLAINSB,
/∗ The segments etc around a point ∗/
PointSegments == pointSegments(getStem : SegmentID,
getUpBranch : SegmentID,
getDownBranch : SegmentID,
getPointDir : Direction),
HasPointPosition ==
pointPos(getPos : PointPosition ↔ setPos) | none,
HasBarrierPosition ==
barrierPos(getPos : BarrierPosition ↔ setPos) | none,
HasSignalStatus ==
signalStatus(getStatus : SignalStatus ↔ setStatus) | none,
/∗ Location/position of a train ∗/
TrainPosition :: frontPos : SegmentPosition ↔ setFrontPos
rearPos : SegmentPosition ↔ setRearPos,
Tick = Real,
HasTicks == ticks(getTicks : Tick) | none,
/∗ From Control ∗/
F.3 Concrete model 405
value
/∗ The tick interval in seconds ∗/
tick interval : Tick,
/∗ Maximal ID numbers ∗/
sbIDSet : ID-set,
segIDSet : ID-set,
trainIDSet : ID-set,
segIDLimit : ID → Bool
segIDLimit(id) ≡
id ∈ segIDSet,
trainIDLimit : ID → Bool
trainIDLimit(id) ≡
id ∈ trainIDSet,
segPosInSBSeg(loc,sbSeg) ≡
case sbSeg of
seg(seg) → isSeg(seg) = getLoc(loc),
point(upSeg,downSeg) → isSeg(upSeg) = getLoc(loc) ∨
isSeg(downSeg) = getLoc(loc),
esa(esa) → isESA(esa) = getLoc(loc)
end,
/∗ Determines if a TrainPosition is
located on one segment ∗/
trainOnlyOnESA : TrainPosition → Bool
trainOnlyOnESA(pos) ≡
case getLoc(frontPos(pos)) of
isESA( ) →
(
F.3 Concrete model 407
case getLoc(rearPos(pos)) of
isESA( ) → true,
→ false
end
),
→ false
end,
axiom
/∗ Two ID0s cannot be identical ∗/
[ is wf id sets ]
sbIDSet ∪ segIDSet ∪ trainIDSet = {}
end
F.3.2 Statics
context: CA Types0, CA SBs0, CA Segs0, CA Trains0, CA ESAs0
scheme CA Statics0(T : CA Types0) =
class
object
SBs : CA SBs0(T),
ESAs : CA ESAs0(T),
Segs : CA Segs0(T),
Trains : CA Trains0(T)
type
/∗ Main railway line configuration type ∗/
Configuration = [Link] × [Link] ×
408 RSL modules
[Link] × [Link]
value
conf : Configuration = ([Link], [Link],
[Link], [Link]),
/∗ Observers ∗/
/∗ ESA observers ∗/
getESASB : [Link] × Configuration → [Link]
getESASB(esa,(sbs,segs,esas,ts)) ≡
[Link](esa,esas),
/∗ SB observers ∗/
getSBSeg : [Link] × [Link] ×
Configuration → [Link]
getSBSeg(sb,dir,(sbs,segs,esas,ts)) ≡
[Link](sb,dir,sbs),
/∗ Segment observers ∗/
getSegSB : [Link] × [Link] ×
Configuration → [Link]
getSegSB(seg,dir,(sbs,segs,esas,ts)) ≡
[Link](seg,dir,segs),
/∗ Train observers ∗/
F.3 Concrete model 409
/∗ Auxiliary functions ∗/
/∗ Determines if a SB is a PointSB ∗/
isPointSB : [Link] × Configuration → Bool
isPointSB(sbID,con) ≡
getSBType(sbID,con) = [Link],
[Link](esa) → getESALength(esa,con),
[Link](seg) → getSegLength(seg,con)
end,
getNextSB(sb,dir,con)
end
pre getSBType(sb,con) = [Link],
[Link](sbID,sbs)
pre getSBType(sbID,(sbs,segs,esas,trains)) = [Link],
/∗ Invariants ∗/
is wf : Configuration → Bool
is wf((sbs,segs,esas,ts)) ≡
[Link] wf(sbs) ∧
[Link] wf(segs) ∧
[Link] wf(esas) ∧
[Link] wf(ts) ∧
composed is wf((sbs,segs,esas,ts)),
sb2 = getNextSB(sb,dir1,con),
pSegs2 = getSBPointSegs(sb2,con)
in
[Link](pSegs1) = [Link](pSegs2) ∧
[Link](pSegs1) = [Link](pSegs2)
end
414 RSL modules
),
tlen = getTrainLength(t,con) ∧
slen = getSegLength(seg,con) ∧
resPoint = getResPoint(con) ∧
brakePoint = getBrakePoint(con)
⇒
slen > (resPoint + tlen) ∧
brakePoint < slen
),
axiom
[ is wf ]
is wf(conf)
end
SBs
context: CA Types0
scheme CA SBs0(T : CA Types0) =
class
type
/∗ Type of interest ∗/
SBs = [Link] → m SBData,
416 RSL modules
value
sbsConf : SBs,
/∗ SB observers ∗/
∼
getSBSeg : [Link] × [Link] × SBs → [Link]
getSBSeg(sb,dir,sbs) ≡
if(dir = [Link])
then
getUpSeg(sbs(sb))
else
getDownSeg(sbs(sb))
end
pre sbExistsInConf(sb,sbs),
∼
getSBType : [Link] × SBs → [Link]
getSBType(sb,sbs) ≡
getType(sbs(sb))
pre sbExistsInConf(sb,sbs),
∼
getPointTicks : [Link] × SBs → [Link]
getPointTicks(sb,sbs) ≡
[Link](getPointTicks(sbs(sb)))
pre getSBType(sb,sbs) = [Link] ∧
sbExistsInConf(sb,sbs),
∼
getBarrierTicks : [Link] × SBs → [Link]
getBarrierTicks(sb,sbs) ≡
[Link](getBarrierTicks(sbs(sb)))
pre getSBType(sb,sbs) = [Link] ∧
sbExistsInConf(sb,sbs),
∼
getSignalTicks : [Link] × SBs → [Link]
getSignalTicks(sb,sbs) ≡
[Link](getSignalTicks(sbs(sb)))
pre getSBType(sb,sbs) = [Link] ∧
sbExistsInConf(sb,sbs),
/∗ Auxiliary functions ∗/
in
case sbSeg of
[Link]( , ) → [Link],
→ [Link]
end
end
pre getSBType(sb,sbs) = [Link],
/∗ Invariants ∗/
is wf : SBs → Bool
is wf(sbs) ≡
sbsHaveConf(sbs) ∧
getSBSeg diff(sbs) ∧
getSBSeg point wf(sbs) ∧
getSBSeg injective(sbs) ∧
getSBSegType wf(sbs),
),
end
Segs
context: CA Types0
scheme CA Segs0(T : CA Types0) =
F.3 Concrete model 419
class
type
/∗ Type of interest ∗/
Segs = SegsData × SegPoints,
value
segsConf : Segs,
/∗ Segment observers ∗/
∼
getSegSB : [Link] × [Link] × Segs → [Link]
getSegSB(seg,dir,(segs,sp)) ≡
if(dir = [Link])
then
getUpSB(segs(seg))
else
getDownSB(segs(seg))
end
pre segExistsInConf(seg,(segs,sp)),
∼
getSegLength : [Link] × Segs → [Link]
getSegLength(seg,(segs,sp)) ≡
getLength(segs(seg))
pre segExistsInConf(seg,(segs,sp)),
∼
getSegMaxSpeed : [Link] × Segs → [Link]
getSegMaxSpeed(seg,(segs,sp)) ≡
getMaxSpeed(segs(seg))
pre segExistsInConf(seg,(segs,sp)),
/∗ Invariant ∗/
is wf : Segs → Bool
is wf(segs) ≡
segsHaveConf(segs) ∧
getSegSB injective(segs) ∧
420 RSL modules
brakeResPoint wf(segs),
/∗∗
∗ The SB in the end of a segment is different
∗ for two different segments or they are the
∗ same in both direction (being branches)
*∗/
getSegSB injective : Segs → Bool
getSegSB injective(segs) ≡
(
∀ seg1, seg2 : [Link],
dir : [Link] •
seg1 6= seg2 ⇒
(
getSegSB(seg1,dir,segs) 6= getSegSB(seg2,dir,segs)
)
∨
(
getSegSB(seg1,[Link],segs) = getSegSB(seg2,[Link],segs) ∧
getSegSB(seg1,[Link],segs) = getSegSB(seg2,[Link],segs)
)
),
end
ESAs
context: CA Types0
scheme CA ESAs0(T : CA Types0) =
class
type
/∗ Type of interest ∗/
ESAs == mk esa(getLowSB : [Link],
getHighSB : [Link],
getLowLength : [Link],
getHighLength : [Link])
F.3 Concrete model 421
value
esasConf : ESAs,
/∗ ESA observers ∗/
∼
getESASB : [Link] × ESAs → [Link]
getESASB(esa,esas) ≡
if(esa = [Link])
then
getLowSB(esas)
else
getHighSB(esas)
end
pre esaExistsInConf(esa,esas),
∼
getESALength : [Link] × ESAs → [Link]
getESALength(esa,esas) ≡
if(esa = [Link])
then
getLowLength(esas)
else
getHighLength(esas)
end
pre esaExistsInConf(esa,esas),
/∗ Invariants ∗/
is wf : ESAs → Bool
is wf(esas) ≡
esasHaveConf(esas),
end
Trains
context: CA Types0
scheme CA Trains0(T : CA Types0) =
class
type
/∗ Type of interest ∗/
Trains = [Link] → m TData,
getMaxSpeed : [Link],
getMaxAcc : [Link],
getMaxDec : [Link])
value
trainsConf : Trains,
/∗ Train observers ∗/
∼
getTrainLength : [Link] × Trains → [Link]
getTrainLength(t,trains) ≡
getLength(trains(t))
pre trainExistsInConf(t,trains),
∼
getTrainMaxSpeed : [Link] × Trains → [Link]
getTrainMaxSpeed(t,trains) ≡
getMaxSpeed(trains(t))
pre trainExistsInConf(t,trains),
∼
getTrainMaxAcc : [Link] × Trains → [Link]
getTrainMaxAcc(t,trains) ≡
getMaxAcc(trains(t))
pre trainExistsInConf(t,trains),
∼
getTrainMaxDec : [Link] × Trains → [Link]
getTrainMaxDec(t,trains) ≡
getMaxDec(trains(t))
pre trainExistsInConf(t,trains),
/∗ Invariants ∗/
is wf : Trains → Bool
is wf(trains) ≡
trainsHaveConf(trains),
end
F.3.3 Dynamics
context: CA Statics0, CA TrainDyn0, CA SBDyn0, CA Types0
scheme CA Dynamics0(T : CA Types0, S : CA Statics0(T)) =
class
object
TD : CA TrainDyn0(T,S),
SD : CA SBDyn0(T,S)
F.3 Concrete model 423
type
/∗ Type of interest ∗/
State = [Link] × [Link]
value
initState : State = ([Link],[Link]),
/∗ Point observer ∗/
∼
getPointPosition : [Link] × State × [Link] → [Link]
getPointPosition(sbID,(ts,sbs),con) ≡
[Link](sbID,sbs,con)
pre [Link](sbID,con) = [Link],
∼
getPointTicks : [Link] × State × [Link] → [Link]
getPointTicks(sbID,(ts,ss),con) ≡
[Link](sbID,ss,con)
pre [Link](sbID,con) = [Link],
/∗ Point generator ∗/
setPointPosition : [Link] × [Link] × State ×
∼
[Link] → State
setPointPosition(sbID,ppos,(ts,ss),con) ≡
(ts,[Link](sbID,ppos,ss,con))
pre [Link](sbID,con) = [Link] ∧
∼trainOnJunction(sbID,con,(ts,ss)),
∼
setPointTicks : [Link] × [Link] × State × [Link] → State
setPointTicks(sbID,tick,(ts,ss),con) ≡
(ts, [Link](sbID,tick,ss,con))
pre [Link](sbID,con) = [Link],
/∗ Crossing observer ∗/
∼
getBarrierPosition : [Link] × State × [Link] → [Link]
getBarrierPosition(sbID,(ts,sbs),con) ≡
[Link](sbID,sbs,con)
pre [Link](sbID,con) = [Link],
∼
getSignalStatus : [Link] × State × [Link] → [Link]
getSignalStatus(sbID,(ts,sbs),con) ≡
[Link](sbID,sbs,con)
pre [Link](sbID,con) = [Link],
∼
getBarrierTicks : [Link] × State × [Link] → [Link]
getBarrierTicks(sbID,(ts,ss),con) ≡
[Link](sbID,ss,con)
pre [Link](sbID,con) = [Link],
∼
getSignalTicks : [Link] × State × [Link] → [Link]
getSignalTicks(sbID,(ts,ss),con) ≡
[Link](sbID,ss,con)
pre [Link](sbID,con) = [Link],
/∗ Crossing generator ∗/
setBarrierPosition : [Link] × [Link] × State ×
∼
[Link] → State
424 RSL modules
setBarrierPosition(sbID,bPos,(ts,sbs),con) ≡
(ts,[Link](sbID,bPos,sbs,con))
pre [Link](sbID,con) = [Link],
∼
setSignalStatus : [Link] × [Link] × State × [Link] → State
setSignalStatus(sbID,sigStat,(ts,sbs),con) ≡
(ts,[Link](sbID,sigStat,sbs,con))
pre [Link](sbID,con) = [Link],
∼
setBarrierTicks : [Link] × [Link] × State × [Link] → State
setBarrierTicks(sbID,tick,(ts,ss),con) ≡
(ts, [Link](sbID,tick,ss,con))
pre [Link](sbID,con) = [Link],
∼
setSignalTicks : [Link] × [Link] × State × [Link] → State
setSignalTicks(sbID,tick,(ts,ss),con) ≡
(ts, [Link](sbID,tick,ss,con))
pre [Link](sbID,con) = [Link],
/∗ Sensor observer ∗/
getSensorStatus : [Link] × State → [Link]
getSensorStatus(sbID,(ts,sbs)) ≡
[Link](sbID,sbs),
/∗ Sensor generator ∗/
∼
setSensorStatus : [Link] × [Link] × State × [Link] → State
setSensorStatus(sbID,senStat,(ts,ss),con) ≡
(ts,[Link](sbID,senStat,ss))
pre sensor guard(sbID,senStat,con,(ts,ss)),
/∗ Train observer ∗/
getTrainAcc : [Link] × State → [Link]
getTrainAcc(tID,(ts,sbs)) ≡
[Link](tID,ts),
/∗ Train generator ∗/
∼
setTrainAcc : [Link] × [Link] × State × [Link] → State
setTrainAcc(tID,acc,(ts,ss),con) ≡
([Link](tID,acc,ts,con),ss)
pre acc ≤ [Link](tID,con) ∧
[Link](tID,con) ≤ acc,
∼
setTrainSpeed : [Link] × [Link] × State × [Link] → State
setTrainSpeed(tID,speed,(ts,ss),con) ≡
F.3 Concrete model 425
([Link](tID,speed,ts,con),ss)
pre speed ≤ [Link](tID,con),
front = [Link](tp),
rear = [Link](tp),
tp = [Link] TrainPosition(rear,front),
s = setTrainDirection(t,dir,s)
in
setTrainPosition(t,tp,s,con)
end,
/∗ Processes ∗/
∼
tick : [Link] × [Link] × State → State
tick(tick,con,s) ≡
let
s = tickPoints(tick,con,s),
s = tickCrossings(tick,con,s),
s = tickTrains(tick,con,s)
in
s
end,
∼
tickPoints : [Link] × [Link] × State → State
tickPoints(tick,con,s) ≡
let
points = { p | p : [Link] • [Link](p,con) = [Link] }
in
pointProcess(points,tick,con,s)
end,
∼
pointProcess : [Link]-set × [Link] × [Link] × State → State
pointProcess(points,tick,con,s) ≡
if(points = {})
then
s
426 RSL modules
else
let
p : [Link] • p ∈ points,
points = points \ {p},
s = updatePoint(p,tick,con,s)
in
pointProcess(points,tick,con,s)
end
end
pre [Link](points,con),
∼
updatePoint : [Link] × [Link] × [Link] × State → State
updatePoint(p,tick,con,s) ≡
let
pp = getPointPosition(p,s,con)
in
case pp of
[Link] → movePoint(p,tick,[Link],s,con),
[Link] → movePoint(p,tick,[Link],s,con),
→s
end
end
pre [Link](p,con) = [Link],
let
c : [Link] • c ∈ crossings,
crossings = crossings \ {c},
s = updateCrossing(c,tick,con,s)
in
crossingProcess(crossings,tick,con,s)
end
end
pre [Link](crossings,con),
∼
updateCrossing : [Link] × [Link] × [Link] × State → State
updateCrossing(cr,tick,con,s) ≡
let
bp = getBarrierPosition(cr,s,con),
ss = getSignalStatus(cr,s,con),
bTicks = [Link](cr,con),
newBTicks = tick + getBarrierTicks(cr,s,con),
sTicks = [Link](cr,con),
newSTicks = tick + getSignalTicks(cr,s,con)
in
case bp of
[Link] →
(
if(ss = [Link])
then
if(newSTicks > sTicks)
then
let
s = setSignalTicks(cr,0.0,s,con),
s = setBarrierPosition(cr,[Link],s,con)
in
s
end
else
setSignalTicks(cr,newSTicks,s,con)
end
else
s
end
),
[Link] →
(
if(newBTicks > bTicks)
then
let
s = setBarrierTicks(cr,0.0,s,con),
s = setBarrierPosition(cr,[Link],s,con),
s = setSignalStatus(cr,[Link],s,con)
in
s
end
else
setBarrierTicks(cr,newBTicks,s,con)
end
428 RSL modules
),
[Link] → s,
[Link] →
(
if(newBTicks > bTicks)
then
let
s = setBarrierTicks(cr,0.0,s,con),
s = setBarrierPosition(cr,[Link],s,con)
in
s
end
else
setBarrierTicks(cr,newBTicks,s,con)
end
)
end
end
pre [Link](cr,con) = [Link],
∼
tickTrains : [Link] × [Link] × State → State
tickTrains(tick,con,s) ≡
let
trains = { t | t : [Link]}
in
trainProcess(trains,tick,con,s)
end,
∼
trainProcess : [Link]-set × [Link] × [Link] × State → State
trainProcess(trains,tick,con,s) ≡
if(trains = {})
then
s
else
let
t : [Link] • t ∈ trains,
trains = trains \ {t},
s = if (trainInESA(t,s)) then s else updateTrain(t,tick,con,s) end
in
trainProcess(trains,tick,con,s)
end
end,
∼
updateTrain : [Link] × [Link] × [Link] × State → State
updateTrain(t,tick,con,s) ≡
let
dir = getTrainDirection(t,s),
acc = getTrainAcc(t,s),
curSpeed = getTrainSpeed(t,s),
newSpeed = curSpeed + acc∗tick,
tp = getTrainPosition(t,s),
deltaProg = curSpeed∗tick + 0.5∗acc∗tick∗tick,
F.3 Concrete model 429
[Link](esa) →
(
let
sb = [Link](esa,con)
in
setSensorStatus(sb,status,s,con)
end
)
end
end,
430 RSL modules
curRearPos = [Link](tp),
curRearPos = updateSegPos(curRearPos,delta,ds,con)
in
[Link] TrainPosition(curFrontPos, curRearPos)
end,
[Link](aSeg) →
(
let
sb = [Link](aSeg,dir,con)
in
case [Link](sb,dir,con) of
[Link](nextSeg) → [Link](nextSeg),
[Link](aESA) → [Link](aESA),
[Link](up,down) → [Link](getSegOfPoint(sb,ds,con))
end
end
)
end,
[Link] →
(
getBarrierPosition(sb,s,con) = [Link]
),
→ false
end
end
else
false
end,
(
∃ dir : [Link], tPos : [Link],
sp1,sp2 : [Link] •
tPos = getTrainPosition(t,ds) ∧
[Link](sp1, [Link](sb,dir,con)) ∧
[Link](sp2, [Link](sb,[Link](dir),con))
),
∃ s : [Link] •
s ∈ segSet ⇒
[Link](s,con)
)
else
false
end
end,
in
if(maxDec 6= curDec)
then
setTrainAcc(t,maxDec,s,con)
else
s
end
end
else
setTrainAcc(t,0.0,s,con)
end,
∼
accelerateTrain : [Link] × [Link] × State → State
accelerateTrain(tID,con,s) ≡
setTrainAcc(tID,[Link](tID,con),s,con),
case dir1 of
[Link] →
(
if (dir1 = dir2)
then
[Link]([Link](tp1),[Link](tp2),con) ⇒
∼[Link]([Link](tp1),[Link](tp2),con)
else
∼[Link]([Link](tp1),[Link](tp2),con)
end
),
[Link] →
(
if (dir1 = dir2) then
∼[Link]([Link](tp1),[Link](tp2),con) ⇒
[Link]([Link](tp1),[Link](tp2),con)
else
[Link]([Link](tp1),[Link](tp2),con)
436 RSL modules
end
)
end
),
/∗ Invariants etc. ∗/
/∗∗
∗ The position of a train may not overlap
∗ with the position of other trains
*∗/
noCollisions : [Link] × State → Bool
noCollisions(con,s) ≡
(
∀ t : [Link] •
∼trainPositionOccupied(t,getTrainPosition(t,s),s,con)
),
/∗∗
∗ Trains cannot end up on same segment
∗ driving in opposite directions away from each other.
∗
∗ If two train are on same segment driving in opposite
∗ directions then the train driving up must be lower
∗ on the line than the train driving down.
*∗/
trainPosPossible : [Link] × State → Bool
trainPosPossible(con,ds) ≡
(
∀ t1,t2 : [Link], segs : [Link]-set,
tp1,tp2 : [Link], seg : [Link] •
commonSegs(t1,t2,ds) 6= {} ∧
(tp1,tp2) = (getTrainPosition(t1,ds),getTrainPosition(t1,ds)) ∧
getTrainDirection(t1,ds) 6= getTrainDirection(t2,ds) ∧
getTrainDirection(t1,ds) = [Link]
⇒
[Link]([Link](tp1),[Link](tp2),con)
),
/∗∗
∗ If the train is located upon a junction,
∗ the point must be connected to the
∗ branch, on which the train is located
*∗/
pointsSafe : [Link] × State → Bool
pointsSafe(con,ds) ≡
(
∀ sb : [Link], t : [Link], seg : [Link] •
F.3 Concrete model 437
trainOnJunction(t,sb,con,ds) ∧
trainOnSegment(t,seg,con,ds) ∧
[Link](seg,con) ⇒
pointConnected(sb,seg,ds,con)
),
/∗ Wellformedness ∗/
is wf : State × [Link] → Bool
is wf((ts,ss),con) ≡
[Link] wf(ts,con) ∧
[Link] wf(ss,con),
axiom
[ wellformedness ]
init req(initState,[Link])
end
TrainDyn
value
initTrainStates : TrainStates,
/∗ Train observer ∗/
∼
getTrainAcc : [Link] × TrainStates → [Link]
getTrainAcc(tID,ts) ≡
438 RSL modules
getTAcc(ts(tID))
pre trainStateExists(tID,ts),
∼
getTrainSpeed : [Link] × TrainStates → [Link]
getTrainSpeed(tID,ts) ≡
getTSpeed(ts(tID))
pre trainStateExists(tID,ts),
∼
getTrainPosition : [Link] × TrainStates →
[Link]
getTrainPosition(tID,ts) ≡
getTPos(ts(tID))
pre trainStateExists(tID,ts),
∼
getTrainDirection : [Link] × TrainStates → [Link]
getTrainDirection (tID,ts) ≡
getTDir(ts(tID))
pre trainStateExists(tID,ts),
/∗ Train generator ∗/
setTrainAcc : [Link] × [Link] × TrainStates ×
∼
[Link] → TrainStates
setTrainAcc(tID,acc,ts,con) ≡
ts † [ tID 7→ setTAcc(acc,ts(tID)) ]
pre acc ≤ [Link](tID,con) ∧
[Link](tID,con) ≤ acc ∧
trainStateExists(tID,ts),
[Link] →
(
[Link]([Link](tp),[Link](tp),con)
)
end
),
∼
getTrainSegments : [Link] × TrainStates →
[Link]-set
getTrainSegments(t,s) ≡
[Link](getTrainPosition(t,s)),
∼
trainInESA : [Link] × TrainStates → Bool
trainInESA(t,s) ≡
[Link](getTrainPosition(t,s)),
∼
trainInESADrivingOut : [Link] × TrainStates → Bool
trainInESADrivingOut(t,s) ≡
if(∼[Link](getTrainPosition(t,s)))
then
false
else
let
segPos = [Link](getTrainPosition(t,s)),
esa = [Link]([Link](segPos)),
dir = getTrainDirection(t,s)
in
T.end2Dir(esa) 6= dir
end
end,
440 RSL modules
∼
trainFrontInESA : [Link] × TrainStates → Bool
trainFrontInESA(t,s) ≡
let
tPos = getTrainPosition(t,s)
in
[Link]([Link](tPos))
end,
∼
trainFrontLoc : [Link] × TrainStates → [Link]
trainFrontLoc(t,ds) ≡
case [Link](getTrainPosition(t,ds)) of
[Link]( ) → [Link](getTrainPosition(t,ds)),
[Link](seg) → [Link](seg)
end,
∼
is wf : TrainStates × [Link] → Bool
is wf(s,con) ≡
allTrainStatesExist(s) ∧
train pos wf(con,s),
getTrainAcc(t,s) = 0.0
),
∼
allTrainsFacingLine : TrainStates → Bool
allTrainsFacingLine(s) ≡
(
∀ t : [Link], esa : [Link] •
[Link](esa) = [Link]([Link](
getTrainPosition(t,s))) ∧
(esa = [Link] ⇒ getTrainDirection(t,s) = [Link]) ∧
(esa = [Link] ⇒ getTrainDirection(t,s) = [Link])
)
end
SBDyn
SBState == mk sbState(
getPP : [Link] ↔ setPP,
getPTicks : [Link] ↔ setPTicks,
getBP : [Link] ↔ setBP,
getSignal : [Link] ↔ setSignal,
getBTicks : [Link] ↔ setBTicks,
getSTicks : [Link] ↔ setSTicks,
getSensor : [Link] ↔ setSensor)
value
initSBStates : SBStates,
/∗ Point observer ∗/
∼
getPointPosition : [Link] × SBStates × [Link] →
[Link]
getPointPosition(p,sbs,con) ≡
[Link](getPP(sbs(p)))
pre [Link](p,con) = [Link] ∧
pointStateExists(p,sbs,con),
∼
getPointTicks : [Link] × SBStates × [Link] →
[Link]
getPointTicks(p,sbs,con) ≡
[Link](getPTicks(sbs(p)))
pre [Link](p,con) = [Link] ∧
pointStateExists(p,sbs,con),
/∗ Point generator ∗/
setPointPosition : [Link] × [Link] × SBStates ×
∼
[Link] → SBStates
setPointPosition(p,pp,sbs,con) ≡
sbs † [ p 7→ setPP([Link](pp),sbs(p)) ]
442 RSL modules
/∗ Crossing observer ∗/
getBarrierPosition : [Link] × SBStates ×
∼
[Link] → [Link]
getBarrierPosition(cr,sbs,con) ≡
[Link](getBP(sbs(cr)))
pre [Link](cr,con) = [Link] ∧
crossingStateExists(cr,sbs,con),
/∗ Crossing generator ∗/
setBarrierPosition : [Link] × [Link] ×
∼
SBStates × [Link] → SBStates
setBarrierPosition(cr,bp,sbs,con) ≡
sbs † [ cr 7→ setBP([Link](bp),sbs(cr)) ]
pre [Link](cr,con) = [Link] ∧
crossingStateExists(cr,sbs,con),
setBarrierTicks(cr,tick,sbs,con) ≡
sbs † [ cr 7→ setBTicks([Link](tick),sbs(cr)) ]
pre [Link](cr,con) = [Link] ∧
crossingStateExists(cr,sbs,con),
/∗ Sensor observer ∗/
∼
getSensorStatus : [Link] × SBStates → [Link]
getSensorStatus(sen,sbs) ≡
getSensor(sbs(sen))
pre sensorStateExists(sen,sbs),
/∗ Sensor generator ∗/
setSensorStatus : [Link] × [Link] ×
∼
SBStates → SBStates
setSensorStatus(sen,ss,sbs) ≡
sbs † [ sen 7→ setSensor(ss,sbs(sen)) ]
pre sensorStateExists(sen,sbs),
/∗ Invariants ∗/
444 RSL modules
∼
is wf : SBStates × [Link] → Bool
is wf(s,con) ≡
allCrossingStatesExist(con,s) ∧
allPointStatesExist(con,s) ∧
allSensorStatesExist(s),
end
F.3 Concrete model 445
F.3.4 Control
type
ControlState = SBCCStates × TCCStates,
SBCCStates = [Link] →
m [Link],
TCCStates = [Link] →
m [Link]
value
initControlState : ControlState,
/∗ Processes ∗/
tick : [Link] × ControlState × [Link] ×
∼
[Link] → out [Link]
(ControlState × [Link])
tick(tick,cs,ds,con) ≡
(
446 RSL modules
let
tSet = [Link],
sbSet = [Link],
(cs,ds) = tickTCCs(tSet,tick,cs,ds,con),
cs = tickSBCCs(sbSet,tick,cs,ds,con)
in
(cs,ds)
end
),
/∗ Communication ∗/
∼
comService : ControlState → in [Link] ControlState
comService(cs) ≡
let
comMsg = [Link]()
in
case [Link](comMsg) of
[Link](sb) →
(
let
sbcc = getSBCCState(sb,cs),
F.3 Concrete model 447
/∗ Invariants ∗/
is wf : ControlState × [Link] × [Link] → Bool
is wf(cs,ds,con) ≡
[Link] wf(ds,con) ∧
tcc has state(cs) ∧
sbcc has state(cs),
/∗∗
∗ Defines that the control system and all its components
∗ must be consistent e.g. the information stored in the
∗ control system must reflect the physical world and
∗ unintended states must not occur.
∗
∗ Also the physical world must abide
∗ by the rules of the control system.
*∗/
consistent : ControlState × [Link] × [Link] → Bool
consistent(cs,ds,con) ≡
is wf(cs,ds,con) ∧
train on branch dir(ds,con) ∧
tcc hasRes passedResPoint(cs,ds,con) ∧
sbcc res wf(cs,con) ∧
position branch sbcc res wf(cs,ds,con) ∧
tcc res branch wf(cs,ds,con) ∧
position sl sbcc res wf(cs,ds,con),
448 RSL modules
∀ t : [Link],
sb : [Link],
tDir : [Link],
seg : [Link],
sbcc : [Link] •
tDir = [Link](t,ds) ∧
[Link](t,seg,con,ds) ∧
[Link](t,con,ds) ∧
[Link](seg,con) ∧
sb = [Link](seg,[Link](tDir),con) ∧
sbcc = getSBCCState(sb,cs)
⇒
[Link](sbcc) = [Link]([Link] res(t,tDir))
),
[Link](t,seg,con,ds) ∧
[Link](seg,con) ∧
sb1 = [Link](seg,[Link](dir),con) ∧
sb2 = [Link](seg,dir,con) ∧
sbcc1 = getSBCCState(sb1,cs) ∧
sbcc2 = getSBCCState(sb2,cs) ∧
res = [Link] res(t,dir) ⇒
[Link](res) = [Link](sbcc1) ∧
[Link](res) = [Link](sbcc2) ∧
([Link](sb2,con) = [Link] ⇒
[Link](res) = [Link](sbcc2))
),
tcc = getTCCState(t,cs) ⇒
[Link](tcc)
),
sbcc = getSBCCState(sb,cs) ⇒
[Link](sbcc)
)
axiom
/∗ The initial state has to be wellformed and
F.3 Concrete model 451
end
TCC
context: CA Types0,
CA Statics0,
CA Dynamics0,
CA ComService0
value
initTCCState : TCCState,
[Link](seg) →
(
let
resPoint = [Link](con),
posFront = [Link](front),
segLength = [Link](seg,con),
dir = [Link](t,ds)
in
passedPoint(posFront,resPoint,segLength,dir)
end
452 RSL modules
)
end
end,
[Link](seg) →
(
let
brkPoint = [Link](con),
posFront = [Link](front),
segLength = [Link](seg,con),
dir = [Link](t,ds)
in
passedPoint(posFront,brkPoint,segLength,dir)
end
)
end
end,
/∗ Processes ∗/
tccMsgReceiver : [Link] × TCCState → TCCState
tccMsgReceiver(comMsg,tcc) ≡
let
resp = [Link](comMsg)
in
case resp of
[Link](resGranted) →
(
let
tcc = setTCCRequesting(false,tcc)
in
F.3 Concrete model 453
if(resGranted)
then
setTCCRes(true,tcc)
else
tcc
end
end
),
→ tcc
end
end,
frontSeg = [Link](isSeg),
segMaxSpeed = [Link](frontSeg,con)
in
if (ts > segMaxSpeed ∨ ts > trainMaxSpeed)
then
decelerateTrain(t,cs,ds,con)
else
checkDeceleration(t,cs,ds,con)
end
454 RSL modules
end
end
end, /∗ let ∗/
else
let
(cs,ds) = if(hasPassedBrakePoint(t,ds,con))
then decelerateTrain(t,cs,ds,con)
else (cs,ds) end
in
if(∼isTCCRequesting(cs))
then
tccRequestRes(t,cs,ds,con)
else
(cs,ds)
end
end
end
else
(cs,ds)
end,
[Link](seg) →
(
(sendTCCReq(t,[Link](seg,dir,con),dir,cs),ds)
)
end /∗ case ∗/
end, /∗ let ∗/
in
[Link](comMsg); cs
end,
/∗ Invariants ∗/
initReq : TCCState → Bool
initReq(tcc) ≡
no tcc res(tcc) ∧
tcc not requesting(tcc) ∧
tcc not decelerating(tcc),
end
SBCC
value
initSBCCState : SBCCState,
in
if(msgList = h i)
then
([Link],sbcc)
else
([Link](hd msgList), setMsgs(tl msgList,sbcc))
end
end,
/∗ Processes ∗/
sbccProcess : [Link] × [Link] × SBCCState × [Link] ×
[Link] → out [Link] SBCCState
sbccProcess(sb,tick,cs,ds,con) ≡
let
cs = sensorProcess(sb,cs,ds,con)
in
if(isPreparing(cs))
then
prepareProcess(sb,cs,ds,con)
else
sbccMsgProcess(sb,cs,ds,con)
end
end,
→ cs
end,
end
else
sbcc
end
end,
→ (cs,ds)
end
end,
[Link] →
(
case [Link](res) of
[Link] →
(
let
ds = [Link](sb,[Link],ds,con)
in
(cs,ds)
end
),
[Link] →
(
let
ds = [Link](sb,[Link],ds,con)
in
(cs,ds)
460 RSL modules
end
)
end
),
→ (cs,ds)
end
end,
[Link] →
(
let
[Link](lineRes) = getLineRes(sbcc),
pointDir = [Link](sb,con)
in
if([Link](lineRes) = pointDir)
then
let
sbcc = removeLineRes(sbcc)
in
sendLDeResMsg(sb,[Link](sb,con)); sbcc
end
else
sendBDeResMsg(sb,[Link](sb,con)); sbcc
end /∗ if ∗/
end /∗ let ∗/
)
end /∗ case ∗/
pre [Link](sb,con),
[Link]( ) →
(
let
(sbcc,retMsg) = handleSBCCMsg(sb,msg,sbcc)
in
case retMsg of
[Link](aMsg) → sendSBCCMsg(sb,sender,aMsg);
sbcc,
→ sbcc
end
end
)
end /∗ case ∗/
),
→ sbcc /∗ no message to process ∗/
end
462 RSL modules
end, /∗ let ∗/
/∗ Response ∗/
[Link]( ) → handleLBResp(sb,msg,sbcc),
/∗ De reservation ∗/
[Link] → handleDeResMsg(msg,sbcc),
[Link] → handleDeResMsg(msg,sbcc),
[Link] → handleDeResMsg(msg,sbcc)
end,
∗/
[Link] →
(
if([Link](res) = [Link](sb,con))
then
let
(cs,ds) = prepareSeg(sb,res,cs,ds,con)
in
([Link],cs,ds)
end
else
if(lineFree(cs))
then
let
cs = setLineRes([Link](res),cs),
cs = sendLBResMsg(sb,
[Link](sb,con),res)
in
([Link],cs,ds)
end
else
([Link]([Link](false)),cs,ds)
end
end
),
→ /∗ PLAINSB, CROSSINGSB ∗/
(
let
(cs,ds) = prepareSeg(sb,res,cs,ds,con)
in
([Link],cs,ds)
end
)
end /∗ case ∗/
end, /∗ let ∗/
else
(sbcc,[Link]([Link](res,false)))
end
end,
/∗ case(msg)
lb → deres line; deres branch
l → deres line;
b → deres branch;
∗/
handleDeResMsg : [Link] × SBCCState →
SBCCState × [Link]
handleDeResMsg(msg,sbcc) ≡
case msg of
[Link] →
(
let
sbcc = removeLineRes(sbcc),
sbcc = removeBranchRes(sbcc)
in
(sbcc,[Link])
F.4 Imperative model 465
end
),
[Link] →
(
let
sbcc = removeLineRes(sbcc)
in
(sbcc,[Link])
end
),
[Link] →
(
let
sbcc = removeBranchRes(sbcc)
in
(sbcc,[Link])
end
)
end,
/∗ Invariants ∗/
initReq : SBCCState → Bool
initReq(sbcc) ≡
no sbcc res(sbcc) ∧
sbcc not preparing(sbcc),
end
/∗ Entity ID types ∗/
ID = Text,
ESAID = End,
SBID = {| sb : ID • sbIDLimit(sb) |},
SegmentID = {| seg : ID • segIDLimit(seg) |},
TrainID = {| t : ID • trainIDLimit(t) |},
/∗ Physical parameters ∗/
Length = Real,
Speed = Real,
Acceleration = Real,
/∗ Neighbour of a SB in a direction ∗/
SBSegment ==
seg(getSeg : SegmentID) |
point(getUpSeg : SegmentID, getDownSeg : SegmentID) |
esa(getESA : ESAID),
/∗ The type of a SB ∗/
SBType == POINTSB | ENDSB | CROSSINGSB | PLAINSB,
/∗ The segments etc around a point ∗/
PointSegments == pointSegments(getStem : SegmentID,
getUpBranch : SegmentID,
getDownBranch : SegmentID,
getPointDir : Direction),
HasPointPosition ==
pointPos(getPos : PointPosition ↔ setPos) | none,
HasBarrierPosition ==
barrierPos(getPos : BarrierPosition ↔ setPos) | none,
HasSignalStatus ==
signalStatus(getStatus : SignalStatus ↔ setStatus) | none,
/∗ Location/position of a train ∗/
TrainPosition :: frontPos : SegmentPosition ↔ setFrontPos
rearPos : SegmentPosition ↔ setRearPos,
Tick = Real,
HasTicks == ticks(getTicks : Tick) | none,
F.4 Imperative model 467
/∗ From Control ∗/
HasRes == res(Reservation) | noRes,
HasSeg == isSeg(SegmentID) | noSeg,
Reservation ==
mk res(getTrain : TrainID, getDir : Direction),
value
/∗ The tick interval in seconds ∗/
tick interval : Tick,
/∗ Maximal ID numbers ∗/
sbIDSet : ID-set,
segIDSet : ID-set,
trainIDSet : ID-set,
segIDLimit : ID → Bool
segIDLimit(id) ≡
id ∈ segIDSet,
trainIDLimit : ID → Bool
trainIDLimit(id) ≡
id ∈ trainIDSet,
/∗ Determines if a TrainPosition is
located on one segment ∗/
trainOnlyOnESA : TrainPosition → Bool
trainOnlyOnESA(pos) ≡
F.4 Imperative model 469
case getLoc(frontPos(pos)) of
isESA( ) →
(
case getLoc(rearPos(pos)) of
isESA( ) → true,
→ false
end
),
→ false
end,
axiom
/∗ Two ID0s cannot be identical ∗/
[ is wf id sets ]
sbIDSet ∪ segIDSet ∪ trainIDSet = {}
end
F.4.2 Statics
context: I Types0, I SBs0, I Segs0, I Trains0, I ESAs0
scheme I Statics0(T : I Types0) =
class
object
SBs : I SBs0(T),
ESAs : I ESAs0(T),
Segs : I Segs0(T),
Trains : I Trains0(T)
470 RSL modules
type
/∗ Main railway line configuration type ∗/
Configuration = [Link] × [Link] ×
[Link] × [Link]
value
conf : Configuration = ([Link], [Link],
[Link], [Link]),
/∗ Observers ∗/
/∗ ESA observers ∗/
getESASB : [Link] → read ESAs.v ESAs [Link]
getESASB(esa) ≡
[Link](esa),
/∗ SB observers ∗/
getSBSeg : [Link] × [Link] → read SBs.v SBs [Link]
getSBSeg(sb,dir) ≡
[Link](sb,dir),
/∗ Segment observers ∗/
getSegSB : [Link] × [Link] →
read Segs.v segs [Link]
getSegSB(seg,dir) ≡
[Link](seg,dir),
/∗ Train observers ∗/
getTrainLength : [Link] → read Trains.v trains [Link]
getTrainLength(tID) ≡
[Link](tID),
getTrainMaxSpeed : [Link] →
read Trains.v trains [Link]
getTrainMaxSpeed(t) ≡
[Link](t),
getTrainMaxAcc : [Link] →
read Trains.v trains [Link]
getTrainMaxAcc(t) ≡
[Link](t),
getTrainMaxDec : [Link] →
read Trains.v trains [Link]
getTrainMaxDec(t) ≡
[Link](t),
/∗ Auxiliary functions ∗/
/∗ Determines if a SB is a PointSB ∗/
isPointSB : [Link] → read SBs.v SBs Bool
isPointSB(sbID) ≡
getSBType(sbID) = [Link],
seg2 ∈ getNextSegSet(seg1,[Link])
)
end
)
end,
getLocLength : [Link] →
read ESAs.v ESAs, Segs.v segs [Link]
getLocLength(loc) ≡
case loc of
[Link](esa) → getESALength(esa),
[Link](seg) → getSegLength(seg)
end,
in
getSingleLineGuard(getNextSB(sb,lineDir),lineDir)
end
pre isLineGuard(sb),
{ getSingleLineGuard(sb,[Link]),
getSingleLineGuard(sb,[Link]) }
end
pre ∼segIsBranch(seg),
/∗ Invariants ∗/
is wf : Unit → read [Link], Segs.v points, SBs.v SBs,
Trains.v trains, ESAs.v ESAs Bool
is wf() ≡
[Link] wf() ∧
[Link] wf() ∧
[Link] wf() ∧
[Link] wf() ∧
composed is wf(),
sb2 = getNextSB(sb,dir1),
pSegs2 = getSBPointSegs(sb2)
in
[Link](pSegs1) = [Link](pSegs2) ∧
[Link](pSegs1) = [Link](pSegs2)
end
),
axiom
[ initial ]
initialise post is wf()
end
SBs
context: I Types0
scheme I SBs0(T : I Types0) =
class
type
/∗ Type of interest ∗/
SBs = [Link] → m SBData,
variable
v SBs : SBs := sbsConf
value
sbsConf : SBs,
/∗ SB observers ∗/
∼
getSBSeg : [Link] × [Link] → read v SBs [Link]
getSBSeg(sb,dir) ≡
if(dir = [Link])
then
getUpSeg(v SBs(sb))
else
getDownSeg(v SBs(sb))
end
pre sbExistsInConf(sb),
∼
getSBType : [Link] → read v SBs [Link]
getSBType(sb) ≡
getType(v SBs(sb))
pre sbExistsInConf(sb),
∼
getPointTicks : [Link] → read v SBs [Link]
getPointTicks(sb) ≡
[Link](getPointTicks(v SBs(sb)))
pre getSBType(sb) = [Link] ∧
sbExistsInConf(sb),
∼
getBarrierTicks : [Link] → read v SBs [Link]
getBarrierTicks(sb) ≡
[Link](getBarrierTicks(v SBs(sb)))
F.4 Imperative model 479
/∗ Auxiliary functions ∗/
/∗ Invariants ∗/
is wf : Unit → read v SBs Bool
is wf() ≡
sbsHaveConf() ∧
getSBSeg diff() ∧
480 RSL modules
end
Segs
context: I Types0
scheme I Segs0(T : I Types0) =
class
type
/∗ Type of interest ∗/
Segs = SegsData × SegPoints,
variable
v segs : SegsData := segsDataConf,
v points : SegPoints := segPointsConf
value
segsConf : Segs = (segsDataConf,segPointsConf),
segsDataConf : SegsData,
segPointsConf : SegPoints,
/∗ Segment observers ∗/
∼
getSegSB : [Link] × [Link] → read v segs [Link]
getSegSB(seg,dir) ≡
if(dir = [Link])
then
getUpSB(v segs(seg))
else
getDownSB(v segs(seg))
end
pre segExistsInConf(seg),
∼
getSegLength : [Link] → read v segs [Link]
getSegLength(seg) ≡
getLength(v segs(seg))
pre segExistsInConf(seg),
∼
getSegMaxSpeed : [Link] → read v segs [Link]
getSegMaxSpeed(seg) ≡
getMaxSpeed(v segs(seg))
pre segExistsInConf(seg),
/∗ Invariant ∗/
is wf : Unit → read v segs, v points Bool
is wf() ≡
segsHaveConf() ∧
getSegSB injective() ∧
brakeResPoint wf(),
/∗∗
∗ The SB in the end of a segment is different
∗ for two different segments or they are the
∗ same in both direction (being branches)
*∗/
getSegSB injective : Unit → read v segs Bool
getSegSB injective() ≡
(
∀ seg1, seg2 : [Link],
dir : [Link] •
seg1 6= seg2 ⇒
(
getSegSB(seg1,dir) 6= getSegSB(seg2,dir)
)
∨
(
getSegSB(seg1,[Link]) = getSegSB(seg2,[Link]) ∧
getSegSB(seg1,[Link]) = getSegSB(seg2,[Link])
)
),
end
ESAs
context: I Types0
scheme I ESAs0(T : I Types0) =
class
type
/∗ Type of interest ∗/
ESAs == mk esa(getLowSB : [Link],
getHighSB : [Link],
getLowLength : [Link],
getHighLength : [Link])
variable
v ESAs : ESAs := esasConf
value
esasConf : ESAs,
/∗ ESA observers ∗/
∼
getESASB : [Link] → read v ESAs [Link]
getESASB(esa) ≡
484 RSL modules
if(esa = [Link])
then
getLowSB(v ESAs)
else
getHighSB(v ESAs)
end
pre esaExistsInConf(esa),
∼
getESALength : [Link] → read v ESAs [Link]
getESALength(esa) ≡
if(esa = [Link])
then
getLowLength(v ESAs)
else
getHighLength(v ESAs)
end
pre esaExistsInConf(esa),
/∗ Invariants ∗/
is wf : Unit → read v ESAs Bool
is wf() ≡
esasHaveConf(),
end
Trains
context: I Types0
scheme I Trains0(T : I Types0) =
class
type
/∗ Type of interest ∗/
Trains = [Link] → m TData,
getMaxDec : [Link])
variable
v trains : Trains := trainsConf
value
trainsConf : Trains,
/∗ Train observers ∗/
∼
getTrainLength : [Link] → read v trains [Link]
getTrainLength(t) ≡
getLength(v trains(t))
pre trainExistsInConf(t),
∼
getTrainMaxSpeed : [Link] → read v trains [Link]
getTrainMaxSpeed(t) ≡
getMaxSpeed(v trains(t))
pre trainExistsInConf(t),
∼
getTrainMaxAcc : [Link] → read v trains [Link]
getTrainMaxAcc(t) ≡
getMaxAcc(v trains(t))
pre trainExistsInConf(t),
∼
getTrainMaxDec : [Link] → read v trains [Link]
getTrainMaxDec(t) ≡
getMaxDec(v trains(t))
pre trainExistsInConf(t),
/∗ Invariants ∗/
is wf : Unit → read v trains Bool
is wf() ≡
trainsHaveConf(),
end
F.4.3 Dynamics
context: I Statics0, I TrainDyn0, I SBDyn0, I Types0
scheme I Dynamics0(T : I Types0, S : I Statics0(T)) =
class
object
486 RSL modules
TD : I TrainDyn0(T,S),
SD : I SBDyn0(T,S)
value
/∗ Point observer ∗/
∼
getPointPosition : [Link] → read [Link].v SBs,
SD.v SBStates [Link]
getPointPosition(sbID) ≡
[Link](sbID)
pre [Link](sbID) = [Link],
∼
getPointTicks : [Link] → read [Link].v SBs, SD.v SBStates [Link]
getPointTicks(sbID) ≡
[Link](sbID)
pre [Link](sbID) = [Link],
/∗ Point generator ∗/
∼
setPointPosition : [Link] × [Link] → read [Link].v SBs
write SD.v SBStates Unit
setPointPosition(sbID,ppos) ≡
[Link](sbID,ppos)
pre [Link](sbID) = [Link] ∧
∼trainOnJunction(sbID),
∼
setPointTicks : [Link] × [Link] → read [Link].v SBs
write SD.v SBStates Unit
setPointTicks(sbID,tick) ≡
[Link](sbID,tick)
pre [Link](sbID) = [Link],
/∗ Crossing observer ∗/
∼
getBarrierPosition : [Link] → read SD.v SBStates [Link]
getBarrierPosition(sbID) ≡
[Link](sbID)
pre [Link](sbID) = [Link],
∼
getSignalStatus : [Link] → read SD.v SBStates [Link]
getSignalStatus(sbID) ≡
[Link](sbID)
pre [Link](sbID) = [Link],
∼
getBarrierTicks : [Link] → read SD.v SBStates [Link]
getBarrierTicks(sbID) ≡
[Link](sbID)
pre [Link](sbID) = [Link],
∼
getSignalTicks : [Link] → read SD.v SBStates [Link]
getSignalTicks(sbID) ≡
[Link](sbID)
pre [Link](sbID) = [Link],
/∗ Crossing generator ∗/
∼
setBarrierPosition : [Link] × [Link] → read [Link].v SBs
write SD.v SBStates Unit
setBarrierPosition(sbID,bPos) ≡
[Link](sbID,bPos)
F.4 Imperative model 487
/∗ Sensor observer ∗/
∼
getSensorStatus : [Link] → read SD.v SBStates [Link]
getSensorStatus(sbID) ≡
[Link](sbID),
/∗ Sensor generator ∗/
∼
setSensorStatus : [Link] × [Link] → write SD.v SBStates Unit
setSensorStatus(sbID,senStat) ≡
[Link](sbID,senStat)
pre sensor guard(sbID,senStat),
/∗ Train observer ∗/
∼
getTrainAcc : [Link] → read TD.v TrainStates [Link]
getTrainAcc(tID) ≡
[Link](tID),
∼
getTrainSpeed : [Link] → read TD.v TrainStates [Link]
getTrainSpeed(tID) ≡
[Link](tID),
∼
getTrainPosition : [Link] → read TD.v TrainStates [Link]
getTrainPosition(tID) ≡
[Link](tID),
∼
getTrainDirection : [Link] → read TD.v TrainStates [Link]
getTrainDirection(tID) ≡
[Link](tID),
front = [Link](tp),
rear = [Link](tp),
488 RSL modules
tp = [Link] TrainPosition(rear,front),
s = setTrainDirection(t,dir)
in
setTrainPosition(t,tp)
end,
/∗ Train generator ∗/
∼
setTrainAcc : [Link] × [Link] → write TD.v TrainStates Unit
setTrainAcc(tID,acc) ≡
([Link](tID,acc))
pre acc ≤ [Link](tID) ∧
[Link](tID) ≤ acc,
∼
setTrainSpeed : [Link] × [Link] → write TD.v TrainStates Unit
setTrainSpeed(tID,speed) ≡
([Link](tID,speed))
pre speed ≤ [Link](tID),
∼
setTrainPosition : [Link] × [Link] →
write TD.v TrainStates Unit
setTrainPosition(tID,pos) ≡
([Link](tID,pos))
pre ∼trainPositionOccupied(tID,pos) ∧
∼tpDerailed(pos,getTrainDirection(tID)),
∼
setTrainDirection : [Link] × [Link] → write TD.v TrainStates Unit
setTrainDirection(tID,dir) ≡
([Link](tID,dir))
pre getTrainSpeed(tID) = 0.0 ∨
getTrainDirection(tID) = dir,
/∗ Processes ∗/
∼
tick : [Link] → read [Link]
write TD.v TrainStates, SD.v SBStates Unit
tick(tick) ≡
tickPoints(tick);
tickCrossings(tick);
tickTrains(tick),
∼
tickPoints : [Link] → read [Link].v SBs
write SD.v SBStates Unit
tickPoints(tick) ≡
let
points = { p | p : [Link] • [Link](p) = [Link] }
in
pointProcess(points,tick)
end,
∼
pointProcess : [Link]-set × [Link] → read [Link].v SBs
write SD.v SBStates Unit
pointProcess(points,tick) ≡
while (points 6= {})
do
let
F.4 Imperative model 489
p : [Link] • p ∈ points,
points = points \ {p},
s = updatePoint(p,tick)
in
pointProcess(points,tick)
end
end
pre [Link](points),
∼
updatePoint : [Link] × [Link] → read [Link].v SBs
write SD.v SBStates Unit
updatePoint(p,tick) ≡
let
pp = getPointPosition(p)
in
case pp of
[Link] → movePoint(p,tick,[Link]),
[Link] → movePoint(p,tick,[Link]),
→ ()
end
end
pre [Link](p) = [Link],
∼
movePoint : [Link] × [Link] × [Link] → read [Link].v SBs
write SD.v SBStates Unit
movePoint(p,tick,pp) ≡
let
ticks = [Link](p),
curTick = getPointTicks(p)
in
if(curTick ≥ ticks)
then
setPointPosition(p,pp);
setPointTicks(p,0.0)
else
setPointTicks(p,curTick+tick)
end
end,
∼
tickCrossings : [Link] → read [Link].v SBs write SD.v SBStates Unit
tickCrossings(tick) ≡
let
crossings = { c | c : [Link] • [Link](c) = [Link] }
in
crossingProcess(crossings,tick)
end,
∼
crossingProcess : [Link]-set × [Link] → read [Link].v SBs
write SD.v SBStates Unit
crossingProcess(crossings,tick) ≡
while (crossings 6= {})
do
let
c : [Link] • c ∈ crossings,
crossings = crossings \ {c},
s = updateCrossing(c,tick)
in
490 RSL modules
crossingProcess(crossings,tick)
end
end
pre [Link](crossings),
∼
updateCrossing : [Link] × [Link] → read [Link].v SBs
write SD.v SBStates Unit
updateCrossing(cr,tick) ≡
let
bp = getBarrierPosition(cr),
ss = getSignalStatus(cr),
bTicks = [Link](cr),
newBTicks = tick + getBarrierTicks(cr),
sTicks = [Link](cr),
newSTicks = tick + getSignalTicks(cr)
in
case bp of
[Link] →
(
if(ss = [Link])
then
if(newSTicks > sTicks)
then
setSignalTicks(cr,0.0);
setBarrierPosition(cr,[Link])
else
setSignalTicks(cr,newSTicks)
end
end
),
[Link] →
(
if(newBTicks > bTicks)
then
setBarrierTicks(cr,0.0);
setBarrierPosition(cr,[Link]);
setSignalStatus(cr,[Link])
else
setBarrierTicks(cr,newBTicks)
end
),
[Link] → (),
[Link] →
(
if(newBTicks > bTicks)
then
setBarrierTicks(cr,0.0);
setBarrierPosition(cr,[Link])
else
setBarrierTicks(cr,newBTicks)
end
)
end
end
F.4 Imperative model 491
tp = getTrainPosition(t),
deltaProg = curSpeed∗tick + 0.5∗acc∗tick∗tick,
deltaProg = if (dir = [Link]) then deltaProg else deltaProg ∗ −1.0 end,
/∗ updating sensor ∗/
if ([Link](tp) 6= [Link](tp2))
then
if (∼[Link](tp2))
then
let
status = [Link],
sensorPos = tp2
in
updateSensor(sensorPos,dir,status)
492 RSL modules
end
else
let
status = [Link],
sensorPos = tp
in
updateSensor(sensorPos,dir,status)
end
end
end
end,
[Link](esa) →
(
let
sb = [Link](esa)
in
setSensorStatus(sb,status)
end
)
end
end,
∼
updateTrainPosition : [Link] × [Link] →
read [Link], SD.v SBStates [Link]
updateTrainPosition(tp,delta) ≡
let
curFrontPos = [Link](tp),
curFrontPos = updateSegPos(curFrontPos,delta),
curRearPos = [Link](tp),
curReartPos = updateSegPos(curRearPos,delta)
in
[Link] TrainPosition(curFrontPos, curRearPos)
end,
∼
updateSegPos : [Link] × [Link] →
read [Link], SD.v SBStates [Link]
F.4 Imperative model 493
updateSegPos(segPos,delta) ≡
let
loc = [Link](segPos),
curProg = [Link](segPos) + delta,
locLength = [Link]([Link](segPos))
in
if (curProg < 0.0 )
then
let
nextLoc = nextLoc(loc,[Link]),
nextPos = [Link](nextLoc) + curProg
in
[Link] SegmentPosition(nextLoc,nextPos)
end
else
if (curProg > locLength)
then
let
nextLoc = nextLoc(loc,[Link]),
nextPos = curProg − locLength
in
[Link] SegmentPosition(nextLoc,nextPos)
end
else
[Link] SegmentPosition(loc,curProg)
end
end
end,
∼
nextLoc : [Link] × [Link] → read [Link], SD.v SBStates [Link]
nextLoc(loc,dir) ≡
case loc of
[Link](esa) →
(
let
sb = [Link](esa),
[Link](aSeg) = [Link](sb,dir)
in
[Link](aSeg)
end
),
[Link](aSeg) →
(
let
sb = [Link](aSeg,dir)
in
case [Link](sb,dir) of
[Link](nextSeg) → [Link](nextSeg),
[Link](aESA) → [Link](aESA),
[Link](up,down) → [Link](getSegOfPoint(sb))
end
end
)
end,
/∗ Auxiliary functions ∗/
tpDerailed : [Link] × [Link] → read [Link].v segs,
[Link].v SBs, SD.v SBStates Bool
tpDerailed(tp,dir) ≡
if (∼[Link](tp) ∧ ∼[Link]([Link](tp))) then
let
seg = [Link]([Link](tp)),
sb = [Link](seg,[Link](dir))
in
case [Link](sb) of
[Link] →
(
if (dir = [Link](sb)) then
pointConnected(sb,[Link]([Link](tp)))
else
pointConnected(sb,[Link]([Link](tp)))
end
),
[Link] →
(
getBarrierPosition(sb) = [Link]
),
→ false
end
F.4 Imperative model 495
end
else
false
end,
∼
getESATrains : [Link] → read TD.v TrainStates [Link]-set
getESATrains(esa) ≡
{ t | t : [Link] • [Link](getTrainPosition(t)) },
∼
getTrainSegments : [Link] → read TD.v TrainStates [Link]-set
getTrainSegments(t) ≡
[Link](t),
∼
getTrainBranch : [Link] → read [Link].v segs, [Link].v SBs,
TD.v TrainStates [Link]
getTrainBranch(t) ≡
(
let
seg : [Link] • seg ∈ getTrainSegments(t) ∧
[Link](seg)
in
seg
end
)
pre (∃ sb : [Link] • trainOnJunction(t,sb)),
∼
trainOnSegment : [Link] × [Link] → read TD.v TrainStates Bool
trainOnSegment(tID,seg) ≡
seg ∈ getTrainSegments(tID),
∼
trainOnJunction : [Link] × [Link] → read [Link].v SBs,
TD.v TrainStates Bool
trainOnJunction(t,sb) ≡
(
[Link](sb) = [Link] ∧
trainOnSensor(t,sb)
),
∼
trainOnJunction : [Link] → read [Link].v SBs, TD.v TrainStates Bool
trainOnJunction(sb) ≡
[Link](sb) = [Link] ∧
trainOnSensor(sb),
∼
trainOnSensor : [Link] × [Link] →
read [Link].v SBs, TD.v TrainStates Bool
trainOnSensor(t,sb) ≡
(
∃ dir : [Link], tPos : [Link],
sp1,sp2 : [Link] •
tPos = getTrainPosition(t) ∧
[Link](sp1, [Link](sb,dir)) ∧
[Link](sp2, [Link](sb,[Link](dir)))
),
∼
trainOnSensor : [Link] → read [Link].v SBs,
TD.v TrainStates Bool
496 RSL modules
trainOnSensor(sb) ≡
(
∃ t : [Link], dir : [Link], tPos : [Link],
sp1,sp2 : [Link] •
tPos = getTrainPosition(t) ∧
[Link](sp1, [Link](sb,dir)) ∧
[Link](sp2, [Link](sb,[Link](dir)))
),
∼
trainInESA : [Link] → read TD.v TrainStates Bool
trainInESA(t) ≡
[Link](t),
∼
trainInESADrivingOut : [Link] → read TD.v TrainStates Bool
trainInESADrivingOut(t) ≡
[Link](t),
∼
trainFrontInESA : [Link] → read TD.v TrainStates Bool
trainFrontInESA(t) ≡
[Link](t),
end
end,
∼
sensor guard : [Link] × [Link] → read [Link].v SBs,
TD.v TrainStates Bool
sensor guard(sen,ss) ≡
(ss = [Link] ∧ trainOnSensor(sen)) ∨
(ss = [Link] ∧ ∼trainOnSensor(sen)),
∼
decelerateTrain : [Link] → read [Link].v trains
write TD.v TrainStates Unit
decelerateTrain(t) ≡
if(getTrainSpeed(t) 6= 0.0)
then
let
maxDec = [Link](t),
curDec = getTrainAcc(t)
in
498 RSL modules
if(maxDec 6= curDec)
then
setTrainAcc(t,maxDec)
end
end
else
setTrainAcc(t,0.0)
end,
∼
accelerateTrain : [Link] → read [Link].v trains
write TD.v TrainStates Unit
accelerateTrain(tID) ≡
setTrainAcc(tID,[Link](tID)),
∼
commonSegs : [Link] × [Link] → read TD.v TrainStates
[Link]-set
commonSegs(tp1,t2) ≡
[Link](tp1) ∩ getTrainSegments(t2),
∼
commonSegs : [Link] × [Link] → read TD.v TrainStates
[Link]-set
commonSegs(t1,t2) ≡
getTrainSegments(t1) ∩ getTrainSegments(t2),
∼
trainPositionOccupied : [Link] × [Link] →
read [Link].v segs, [Link].v SBs,
TD.v TrainStates Bool
trainPositionOccupied(t1,tp1) ≡
(
∀ segs : [Link]-set, dir1,dir2 : [Link],
tp1,tp2 : [Link] •
∃ t2 : [Link] •
t2 6= t1 ∧
segs = commonSegs(tp1,t2) ∧
segs 6= {} ∧
(dir1,dir2) = (getTrainDirection(t1),getTrainDirection(t2)) ∧
tp2 = getTrainPosition(t2) ∧
case dir1 of
[Link] →
(
if (dir1 = dir2)
then
[Link]([Link](tp1),[Link](tp2)) ⇒
∼[Link]([Link](tp1),[Link](tp2))
else
∼[Link]([Link](tp1),[Link](tp2))
end
),
[Link] →
(
if (dir1 = dir2) then
∼[Link]([Link](tp1),[Link](tp2)) ⇒
[Link]([Link](tp1),[Link](tp2))
else
[Link]([Link](tp1),[Link](tp2))
F.4 Imperative model 499
end
)
end
),
/∗ Invariants etc. ∗/
/∗∗
∗ The position of a train may not overlap
∗ with the position of other trains
*∗/
∼
noCollisions : Unit → read [Link].v segs, [Link].v SBs,
TD.v TrainStates Bool
noCollisions() ≡
(
∀ t : [Link] •
∼trainPositionOccupied(t,getTrainPosition(t))
),
/∗∗
∗ Trains cannot end up on same segment
∗ driving in opposite directions away from each other.
∗
∗ If two train are on same segment driving in opposite
∗ directions then the train driving up must be lower
∗ on the line than the train driving down.
*∗/
∼
trainPosPossible : Unit → read [Link].v segs, [Link].v SBs,
TD.v TrainStates Bool
trainPosPossible() ≡
(
∀ t1,t2 : [Link], segs : [Link]-set,
tp1,tp2 : [Link], seg : [Link] •
commonSegs(t1,t2) 6= {} ∧
(tp1,tp2) = (getTrainPosition(t1),getTrainPosition(t1)) ∧
getTrainDirection(t1) 6= getTrainDirection(t2) ∧
getTrainDirection(t1) = [Link]
⇒
[Link]([Link](tp1),[Link](tp2))
),
/∗∗
∗ If the train is located upon a junction,
∗ the point must be connected to the
∗ branch, on which the train is located
*∗/
∼
pointsSafe : Unit → read [Link].v segs, [Link].v SBs,
TD.v TrainStates, SD.v SBStates Bool
500 RSL modules
pointsSafe() ≡
(
∀ sb : [Link], t : [Link], seg : [Link] •
trainOnJunction(t,sb) ∧
trainOnSegment(t,seg) ∧
[Link](seg) ⇒
pointConnected(sb,seg)
),
/∗ Wellformedness ∗/
∼
is wf : Unit → read [Link], TD.v TrainStates, SD.v SBStates Bool
is wf() ≡
[Link] wf() ∧
[Link] wf() ∧
[Link] wf(),
∼
init req : Unit → read [Link], TD.v TrainStates, SD.v SBStates Bool
init req() ≡
is wf() ∧
[Link] req() ∧
[Link] req()
axiom
[ Initial state ]
initialise post init req()
end
TrainDyn
TrainState == mk tState(
getTAcc : [Link] ↔ setTAcc,
getTSpeed : [Link] ↔ setTSpeed,
getTPos : [Link] ↔ setTPos,
getTDir : [Link] ↔ setTDir)
variable
v TrainStates : TrainStates := initTrainStates
F.4 Imperative model 501
value
initTrainStates : TrainStates,
/∗ Train observer ∗/
getTrainAcc : [Link] → read v TrainStates [Link]
getTrainAcc(t) ≡
getTAcc(v TrainStates(t)),
getTrainPosition : [Link] →
read v TrainStates [Link]
getTrainPosition(t) ≡
getTPos(v TrainStates(t))
pre trainStateExists(t),
getTrainDirection : [Link] →
read v TrainStates [Link]
getTrainDirection (t) ≡
getTDir(v TrainStates(t))
pre trainStateExists(t),
/∗ Train generator ∗/
setTrainAcc : [Link] × [Link] →
write v TrainStates Unit
setTrainAcc(t,acc) ≡
v TrainStates := v TrainStates †
[ t 7→ setTAcc(acc,v TrainStates(t)) ]
pre acc ≤ [Link](t) ∧
[Link](t) ≤ acc ∧
trainStateExists(t),
[Link] →
(
[Link]([Link](tp),[Link](tp))
)
end
),
getTrainSegments : [Link] →
read v TrainStates [Link]-set
getTrainSegments(t) ≡
[Link](getTrainPosition(t)),
∼
trainInESA : [Link] → read v TrainStates Bool
trainInESA(t) ≡
[Link](getTrainPosition(t)),
∼
trainInESADrivingOut : [Link] →
read v TrainStates Bool
trainInESADrivingOut(t) ≡
if(∼[Link](getTrainPosition(t)))
then
false
F.4 Imperative model 503
else
let
segPos = [Link](getTrainPosition(t)),
esa = [Link]([Link](segPos)),
dir = getTrainDirection(t)
in
T.end2Dir(esa) 6= dir
end
end,
trainInESA(t)
),
end
SBDyn
SBState == mk sbState(
getPP : [Link] ↔ setPP,
getPTicks : [Link] ↔ setPTicks,
getBP : [Link] ↔ setBP,
getSignal : [Link] ↔ setSignal,
getBTicks : [Link] ↔ setBTicks,
getSTicks : [Link] ↔ setSTicks,
getSensor : [Link] ↔ setSensor)
variable
v SBStates : SBStates := initSBStates
value
initSBStates : SBStates,
/∗ Point observer ∗/
∼
getPointPosition : [Link] → read v SBStates [Link]
getPointPosition(p) ≡
[Link](getPP(v SBStates(p)))
pre [Link](p) = [Link] ∧
pointStateExists(p),
∼
getPointTicks : [Link] → read v SBStates [Link]
getPointTicks(p) ≡
[Link](getPTicks(v SBStates(p)))
F.4 Imperative model 505
/∗ Point generator ∗/
∼
setPointPosition : [Link] × [Link] →
write v SBStates Unit
setPointPosition(p,pp) ≡
v SBStates := v SBStates †
[ p 7→ setPP([Link](pp),v SBStates(p)) ]
pre [Link](p) = [Link] ∧
pointStateExists(p),
∼
setPointTicks : [Link] × [Link] → write v SBStates Unit
setPointTicks(p,tick) ≡
v SBStates := v SBStates †
[ p 7→ setPTicks([Link](tick),v SBStates(p)) ]
pre [Link](p) = [Link] ∧
pointStateExists(p),
/∗ Crossing observer ∗/
∼
getBarrierPosition : [Link] →
read v SBStates [Link]
getBarrierPosition(cr) ≡
[Link](getBP(v SBStates(cr)))
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
∼
getSignalStatus : [Link] → read v SBStates [Link]
getSignalStatus(cr) ≡
[Link](getSignal(v SBStates(cr)))
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
∼
getBarrierTicks : [Link] → read v SBStates [Link]
getBarrierTicks(cr) ≡
[Link](getBTicks(v SBStates(cr)))
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
∼
getSignalTicks : [Link] → read v SBStates [Link]
getSignalTicks(cr) ≡
[Link](getSTicks(v SBStates(cr)))
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
/∗ Crossing generator ∗/
∼
setBarrierPosition : [Link] × [Link] →
write v SBStates Unit
setBarrierPosition(cr,bp) ≡
v SBStates := v SBStates †
[ cr 7→ setBP([Link](bp),v SBStates(cr)) ]
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
∼
setSignalStatus : [Link] × [Link] →
write v SBStates Unit
506 RSL modules
setSignalStatus(cr,ss) ≡
v SBStates := v SBStates †
[ cr 7→ setSignal([Link](ss),v SBStates(cr)) ]
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
∼
setBarrierTicks : [Link] × [Link] → write v SBStates Unit
setBarrierTicks(cr,tick) ≡
v SBStates := v SBStates †
[ cr 7→ setBTicks([Link](tick),v SBStates(cr)) ]
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
∼
setSignalTicks : [Link] × [Link] → write v SBStates Unit
setSignalTicks(cr,tick) ≡
v SBStates := v SBStates †
[ cr 7→ setSTicks([Link](tick),v SBStates(cr)) ]
pre [Link](cr) = [Link] ∧
crossingStateExists(cr),
/∗ Sensor observer ∗/
∼
getSensorStatus : [Link] → read v SBStates [Link]
getSensorStatus(sen) ≡
getSensor(v SBStates(sen))
pre sensorStateExists(sen),
/∗ Sensor generator ∗/
∼
setSensorStatus : [Link] × [Link] →
write v SBStates Unit
setSensorStatus(sen,ss) ≡
v SBStates := v SBStates †
[ sen 7→ setSensor(ss,v SBStates(sen)) ]
pre sensorStateExists(sen),
getPTicks(state) 6= [Link]
end
pre sensorStateExists(sb) ∧
[Link](sb) = [Link],
/∗ Invariants ∗/
∼
is wf : Unit → read [Link].v SBs, v SBStates Bool
is wf() ≡
allCrossingStatesExist() ∧
allPointStatesExist() ∧
allSensorStatesExist(),
end
F.4.4 Control
context: I Dynamics0, I ComService0, I SBCC0, I TCC0
scheme I Control0(T : I Types0, S : I Statics0(T),
D : I Dynamics0(T,S)) =
class
type
SBCCIndex = {| n : Nat • n > 0 ∧ n ≤ card [Link] |},
TCCIndex = {| n : Nat • n > 0 ∧ n ≤ card [Link] |}
object
COM : I ComService0(T),
SBCC[ n : SBCCIndex ] : I SBCC0(T,S,D,COM),
TCC[ n : TCCIndex ] : I TCC0(T,S,D,COM)
value
sbIndex : [Link] →m Nat,
tIndex : [Link] →
m Nat,
/∗ Processes ∗/
∼
tick : [Link] → read [Link], {TCC[ t ].v tccRes | t : Nat}
write {SBCC[ t ].any | t : Nat}, [Link],
{TCC[ t ].any | t : Nat}
out [Link] Unit
tick(tick) ≡
(
tickTCCs([Link],tick);
tickSBCCs([Link],tick); ()
),
∼
tickSBCCs : [Link]-set × [Link] →
read [Link], {TCC[ t ].v tccRes | t : Nat}
write {SBCC[ t ].any | t : Nat}, [Link]
out [Link] Unit
tickSBCCs(sbSet,tick) ≡
while(sbSet 6= {})
do
F.4 Imperative model 509
let
sb : [Link] • sb ∈ sbSet,
sbSet = sbSet \ {sb}
in
SBCC[ sbIndex(sb) ].sbccProcess(sb,tick)
end
end,
∼
tickTCCs : [Link]-set × [Link] →
read [Link], {TCC[ t ].v tccRes | t : Nat}
write [Link], {TCC[ t ].any | t : Nat}
out [Link] Unit
tickTCCs(tSet,tick) ≡
while(tSet = {})
do
let
t : [Link] • t ∈ tSet,
tSet = tSet \ {t}
in
TCC[ tIndex(t) ].tccProcess(t,tick)
end
end,
/∗ Communication ∗/
∼
comService : Unit → write {SBCC[ t ].any | t : Nat},
{TCC[ t ].any | t : Nat}
in [Link] Unit
comService() ≡
let
comMsg = [Link]()
in
case [Link](comMsg) of
[Link](sb) →
(
SBCC[ sbIndex(sb) ].msgReceiver(comMsg); ()
),
[Link](t) →
(
TCC[ tIndex(t) ].tccMsgReceiver(comMsg); ()
)
end
end,
/∗ Invariants ∗/
is wf : Unit → read [Link], [Link], {TCC[ t ].any | t : Nat},
{SBCC[ t ].any | t : Nat}
out [Link] Bool
is wf() ≡
tcc has state() ∧
sbcc has state(),
/∗∗
∗ Defines that the control system and all its
∗ components must be consistent e.g. the information
∗ stored in the control system must reflect the
∗ physical world and unintended states must not occur.
∗
∗ Also the physical world must abide by the
∗ rules of the control system.
*∗/
consistent : Unit → read [Link], [Link],
{TCC[ t ].any | t : Nat},
{SBCC[ t ].any | t : Nat}
out [Link] Bool
consistent() ≡
is wf() ∧
train on branch dir() ∧
tcc hasRes passedResPoint() ∧
sbcc res wf() ∧
position branch sbcc res wf() ∧
tcc res branch wf() ∧
position sl sbcc res wf(),
end
F.4 Imperative model 513
TCC
variable
v tccRes : Bool := hasTCCRes(initTCCState),
v isReq : Bool := isTCCRequesting(initTCCState),
v isDec : Bool := isTrainDecelerating(initTCCState)
value
initTCCState : TCCState,
hasPassedResPoint : [Link] →
read [Link].v TrainStates, [Link].v ESAs,
[Link].v points, [Link].v segs Bool
hasPassedResPoint(t) ≡
let
front = [Link]([Link](t))
in
case [Link](front) of
[Link](esa) →
(
let
resPoint = [Link](),
posFront = [Link](front),
esaLength = [Link](esa),
514 RSL modules
dir = [Link](t)
in
passedPoint(posFront,resPoint,esaLength,dir)
end
),
[Link](seg) →
(
let
resPoint = [Link](),
posFront = [Link](front),
segLength = [Link](seg),
dir = [Link](t)
in
passedPoint(posFront,resPoint,segLength,dir)
end
)
end
end,
hasPassedBrakePoint : [Link] →
read [Link].v TrainStates, [Link].v ESAs,
[Link].v points, [Link].v segs Bool
hasPassedBrakePoint(t) ≡
let
front = [Link]([Link](t))
in
case [Link](front) of
[Link](esa) →
(
let
brkPoint = [Link](),
posFront = [Link](front),
esaLength = [Link](esa),
dir = [Link](t)
in
passedPoint(posFront,brkPoint,esaLength,dir)
end
),
[Link](seg) →
(
let
brkPoint = [Link](),
posFront = [Link](front),
segLength = [Link](seg),
dir = [Link](t)
in
passedPoint(posFront,brkPoint,segLength,dir)
end
)
end
end,
case dir of
[Link] → posFront > (segLength − passPoint),
[Link] → posFront < passPoint
end,
/∗ Processes ∗/
tccMsgReceiver : [Link] → write v isReq, v tccRes Unit
tccMsgReceiver(comMsg) ≡
let
resp = [Link](comMsg)
in
case resp of
[Link](resGranted) →
(
setTCCRequesting(false);
if(resGranted)
then
setTCCRes(true)
end
),
→ ()
end
end,
frontSeg = [Link](isSeg),
segMaxSpeed = [Link](frontSeg)
in
if (ts > segMaxSpeed ∨ ts > trainMaxSpeed)
then
decelerateTrain(t)
else
checkDeceleration(t)
end
end
end
end, /∗ let ∗/
∼
checkDeceleration : [Link] →
write [Link].v TrainStates, v isDec Unit
checkDeceleration(t) ≡
if (isTrainDecelerating())
then
[Link](t,0.0);
setTrainDecelerating(false)
end,
if(∼isTCCRequesting())
then
tccRequestRes(t); ()
end
end
end,
∼
tccRequestRes : [Link] →
read [Link].v ESAs, [Link].v segs,
[Link].v TrainStates
write v isReq out [Link] Unit
tccRequestRes(t) ≡
let
loc = [Link]([Link](t)),
dir = [Link](t)
in
case loc of
[Link](esa) →
(
/∗ If not facing line, then do nothing.
Will brake at brakepoint ∗/
if (dir = T.end2Dir(esa))
then
()
else
sendTCCReq(t,[Link](esa),dir)
end
),
[Link](seg) →
(
sendTCCReq(t,[Link](seg,dir),dir)
)
end /∗ case ∗/
end, /∗ let ∗/
∼
sendTCCReq : [Link] × [Link] × [Link] →
write v isReq out [Link] Unit
sendTCCReq(t,sb,dir) ≡
let
sender = [Link](t),
receiver = [Link](sb),
res = [Link] res(t,dir),
msg = [Link](res),
comMsg = [Link] comMsg(sender,receiver,msg),
cs = setTCCRequesting(true)
in
[Link](comMsg)
end,
/∗ Invariants ∗/
initReq : Unit → read v tccRes, v isReq, v isDec Bool
initReq() ≡
no tcc res() ∧
tcc not requesting() ∧
tcc not decelerating(),
518 RSL modules
axiom
/∗ Initial state ∗/
[ initial ]
initialise post initReq()
end
SBCC
variable
v lineRes : [Link] := getLineRes(initSBCCState),
v branchRes : [Link] := getBranchRes(initSBCCState),
v sensorStatus : [Link] :=
getSensorStatus(initSBCCState),
v msgs : [Link]∗ := getMsgs(initSBCCState),
v prepRes : [Link] := getPrepRes(initSBCCState)
value
initSBCCState : SBCCState,
/∗ Processes ∗/
sbccProcess : [Link] × [Link] →
read [Link].v SBs, [Link].v segs
write any, [Link].v SBStates
out [Link] Unit
sbccProcess(sb,tick) ≡
sensorProcess(sb);
if(isPreparing())
then
prepareProcess(sb)
else
sbccMsgProcess(sb)
end,
→ ()
end,
sensorProcess(sb) ≡
let
sState = [Link](sb),
lastState = v sensorStatus
in
v sensorStatus := sState;
→ ()
end,
case [Link](sb) of
[Link] → [Link](sb,[Link]); (),
[Link] →
(
case [Link](res) of
[Link] → [Link](sb,[Link]); (),
[Link] → [Link](sb,[Link]); ()
end
),
→ ()
end,
endDir = [Link](sb)
in
if([Link](lineRes) = endDir)
then
removeLineRes();
sendLDeResMsg(sb,[Link](sb)); ()
end /∗ if ∗/
end /∗ let ∗/
),
[Link] →
(
let
[Link](lineRes) = v lineRes,
pointDir = [Link](sb)
in
if([Link](lineRes) = pointDir)
then
removeLineRes();
sendLDeResMsg(sb,[Link](sb)); ()
else
sendBDeResMsg(sb,[Link](sb)); ()
end /∗ if ∗/
end /∗ let ∗/
)
end /∗ case ∗/
pre [Link](sb),
case hasComMsg of
[Link]([Link] comMsg(sender,receiver,msg)) →
(
case sender of
[Link]( ) →
(
let
retMsg = handleTCCMsg(sb,msg)
in
case retMsg of
[Link](aMsg) →
sendSBCCMsg(sb,sender,aMsg); (),
→ ()
end
end
),
[Link]( ) →
(
let
retMsg = handleSBCCMsg(sb,msg)
in
case retMsg of
[Link](aMsg) →
sendSBCCMsg(sb,sender,aMsg); (),
→ ()
end
end
)
end /∗ case ∗/
),
→ () /∗ no message to process ∗/
end
end, /∗ let ∗/
/∗ Response ∗/
[Link]( ) → handleLBResp(sb,msg),
/∗ De reservation ∗/
[Link] → handleDeResMsg(msg),
[Link] → handleDeResMsg(msg),
[Link] → handleDeResMsg(msg)
end,
[Link](res) = msg
in
case [Link](sb) of
[Link] →
(
/∗ if direction away from end → send msg
else OK
∗/
if([Link](res) = [Link](sb))
then
prepareSeg(sb,res);
[Link]
else
if(lineFree())
then
v lineRes := [Link](res);
sendLBResMsg(sb,[Link](sb),res);
[Link]
else
[Link]([Link](false))
end
end
),
→ /∗ PLAINSB, CROSSINGSB ∗/
(
prepareSeg(sb,res);
[Link]
)
end /∗ case ∗/
end, /∗ let ∗/
/∗ case(msg)
lb → deres line; deres branch
l → deres line;
b → deres branch;
∗/
handleDeResMsg : [Link] → write any [Link]
handleDeResMsg(msg) ≡
case msg of
526 RSL modules
[Link] →
(
removeLineRes();
removeBranchRes();
[Link]
),
[Link] →
(
removeLineRes();
[Link]
),
[Link] →
(
removeBranchRes();
[Link]
)
end,
/∗ Invariants ∗/
initReq : Unit → read any Bool
initReq() ≡
no sbcc res() ∧
sbcc not preparing(),
axiom
/∗ Initial state ∗/
[ initial ]
initialise post initReq()
end