Imm 7009
Imm 7009
Compositional Verification of
Railway Interlocking Systems
Master Thesis
Cebrail Erdogan
Cebrail Erdogan
[email protected]
DTU Compute
Richard Petersens Plads
Building 303b
2800 Kgs. Lyngby
DENMARK
The thesis deals with the development of a decomposition tool supporting the Robust-
RailS’ verification of railway interlocking systems.
The project period for the thesis was from January 2nd, 2017 to August 4th, 2017.
Cebrail Erdogan
vi
Acknowledgements
I would first like to thank my thesis advisor Professor Anne E. Haxthausen of the
Department of Applied Mathematics and Computer Science at DTU. The door to
Prof. Haxthausen office was always open whenever I ran into a trouble spot or had
a question about my software development or writing. She consistently allowed this
paper to be my own work but steered me in the right the direction whenever she
thought I needed it.
I would also like to acknowledge Linh Hong Vu and Hugo Daniel at DTU with
their assistance on using the verification tool and providing materials.
Finally, I must express my very profound gratitude to my family for providing me
with unfailing support and continuous encouragement throughout my years of study
and through the process of writing this thesis. This accomplishment would not have
been possible without them. Thank you.
viii
Contents
Summary i
Sammenfatning iii
Preface v
Acknowledgements vii
Contents ix
1 Introduction 1
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Goal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Thesis Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2 Background 3
2.1 RobustRailS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Railway Interlocking System . . . . . . . . . . . . . . . . . . . . . . 3
2.3 Existing Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4 GUI Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.5 Raise Specification Language . . . . . . . . . . . . . . . . . . . . . 8
3 Analysis 9
3.1 Intended use of Tool . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.2 Cuts and Decomposition Methods . . . . . . . . . . . . . . . . . . . 9
3.3 Border Cut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.4 Border Cut Conditions . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.5 Soundness Conditions . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.6 Decomposition Methods . . . . . . . . . . . . . . . . . . . . . . . . 13
3.7 Other cut types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4 Requirements 21
4.1 Functional Requirements . . . . . . . . . . . . . . . . . . . . . . . . 21
4.2 Non-Functional Requirements . . . . . . . . . . . . . . . . . . . . . 21
4.3 RSL Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5 Design 29
5.1 RSL Modules Overview . . . . . . . . . . . . . . . . . . . . . . . . 29
x Contents
7 Experiments 61
7.1 Goal of the Experiments . . . . . . . . . . . . . . . . . . . . . . . . 61
7.2 Experimental Approach . . . . . . . . . . . . . . . . . . . . . . . . 61
7.3 Mini Extended . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
7.4 EDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
7.5 Roskilde station . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
8 Discussion 67
8.1 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
8.2 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
8.3 Directions for Future Work . . . . . . . . . . . . . . . . . . . . . . 68
9 Conclusion 69
D Tests 87
D.1 Decomposition_TEST . . . . . . . . . . . . . . . . . . . . . . . . . 87
D.2 RSL Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
D.3 C++ Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Contents xi
E RSL Specifications 95
E.1 Decomposition_DESIGN . . . . . . . . . . . . . . . . . . . . . . . 95
E.2 Decomposition_COMMON . . . . . . . . . . . . . . . . . . . . . . 97
Bibliography 115
xii
CHAPTER 1
Introduction
The overall goal of this project is to provide a command line tool, that can be used
for decomposition of future Danish interlocking systems. In this chapter, we will
motivate for this, explain the goal of the project, and at last give an overview of report
structure.
1.1 Motivation
The Danish Railway system is moving towards a new digital interlocking system [10],
along with the rest of the Europe. With that said, it is only expected that new
tools are introduced for a more integrated system in the future compatible with the
standardized European Train Control System (ETCS) Level 2 [15].
An interlocking system controls the dynamic allocation of routes for trains and
thereby creating a safe system where trains can safely travel through the network
without colliding and derailing. The overall purpose of the new interlocking system is
to make the interlocking safer and smarter.
The Danish Council for Strategic Research has funded the project RobustRailS[12].
One of its goals is to provide methods and tools for formal verifications of railway inter-
locking systems. DTU has an active part of this project and amongst its contributions,
it does also develop software.
A verification tool for interlocking systems is already in existence in the form of a
command line interface (CLI), developed as part of the RobustRailS project in DTU
[13]. Although the tools exist, the verification can be a problem when processing large
networks as it may fail to give results due to the state space explosion problem, often
seen in model-checkers [6]. A temporary workaround for this has been to decompose
networks defined in XML files manually. This process is not user-friendly and takes
too much time.
1.2 Goal
The goal of this project is to tackle the state space explosion problem by providing a
decomposition tool which converts big networks into smaller chunks. It will provide
a user-friendly experience that will make it possible to generate sub-networks easily
from a given cut specification.
The decomposition tool must preserve the network safety properties when applying
cuts. This ensures that the sub-networks are valid representations that can be used
2 1 Introduction
with the verification tool. The developed tool should be extendible, such that a
developer may with ease add new cut types.
A tool that achieves these goals will support the compositional verification by
providing a decomposition solution.
Specification
Linear Point
Figure 2.1: Domain specific language of the interlocking system. Solid arrows points
to sub-elements and hollow arrows points to base elements.
The specification elements in this domain specific language are described in the
subsequent subsections. For simplicity, we do not consider level crossing since it has
no relevance in this dissertation.
DOWN mb20 UP
t20
mb11 mb12 mb21 mb15
A linear is a type of section and contains at most two neighbors, one in every
end. The linear sections are represented as straight lines. If a linear only contains one
neighbor, then it is called a boundary, which can be identified by the dashed lines on
its disconnected side. A linear has only two properties, its neighbors, and its length.
In Mini layout (Figure 2.2), the linear sections are b10, t10 t20, t12, t14 and b14,
2.2 Railway Interlocking System 5
A point is also a type of section and contains three ends connected to different
sections. The three ends are known as stem, plus and minus. The stem is the lone
end in the opposite direction of plus and minus. The plus end is parallel to the stem.
The plus- and stem end can be seen as a linear section as they represent the straight
sub section of a point. The minus end of a point diverts from away this linear section
and creates a branch in the network. A point also has two properties, its neighbors,
and its length. The points in Mini layout are t11 and t13.
MINUS
STEM PLUS
Figure 2.3: A point with its three ends. A point can face any direction.
It is possible for two different points to have their minus ends connected to each
other. An example is shown in Figure 2.4.
t13
t11 T16
Figure 2.4: Two points connected to each other. An excerpt of Figure 3.19.
A marker board also called a signal, is mounted in one of the ends of a linear
section. It can only be seen in one direction. If its direction is up, then it can only be
seen by a train moving the same direction and vice versa. A marker board can not
exist on the disconnected side of a boundary. Additionally, it has a distance to the
end it is facing. So, in total, a marker board has three properties: A reference to a
linear section, a direction, and a distance.
mb11
b10 t10
mb10
Figure 2.5: Marker boards with different directions. The figure is a excerpt from Mini
layout.
6 2 Background
Table 2.1: An excerpt of an interlocking table for the network layout in Figure 2.2 [6].
The overlap column is ommited, since no overlaps exists in this table.
As it can be seen in Figure 2.6, the tool chain has several steps. In the first box
(yellow), the given network and the generated interlocking table are statically checked.
This verifies if the input is well formed or not, if not, then the correctness of the
network is not checked. It is a requirement that the given specification must comply
with the static semantic rules defined for the DSL. Note that the generation of an
interlocking table is optional.
In case of a successful static check, a model instance will be generated from a
generic model which describes the dynamic behavior of the Danish interlocking system.
Concurrently, safety properties are generated from given specification, which runs
through the defined safety-properties.
Finally, the generated model instance is verified against the safety properties using
a combination of bounded model checking (BMC) and inductive reasoning. If the
model instance does not satisfy the properties, counterexamples will be generated.
Network
Sub-network
....
Decompose
Sub-network
Cut
Specification
The decomposition tool accepts network layout and a cut specification in XML-
format. The network and cut specification will be parsed, and the network will be
decomposed. This might result in two or more sub-networks, which must all be verified
with the verification tool.
the properties of the cut. The described cuts in this paper are border cut, linear cut,
and horizontal cut. Only border cut is implemented of the listed.
A decomposition method, on the other hand, takes a cut, or a set of cuts as an
input. It applies the cuts with a specified algorithm that is suited for a specific scenario.
The described decomposition methods in this paper are: single cut (decomposition),
cluster cut (decomposition) and multi cut (decomposition).
The description here focuses on the application of the cuts and methods, and not
their type specifications, where the differences between them are not as clear.
DOWN UP
mb2 mb4
b1 t2 t3 b4
(section (section
down) mb3 up) mb5
b1 t2 t3 t2 t3 b4
mb3 mb5
mb3
Figure 3.3: Down sub-network. Figure 3.4: Up sub-network.
Notice that the marker board mb5 is removed in down sub-network and mb2
is removed in up sub-network since they are no longer valid. The two given linear
sections (t2 and t3 ) are preserved in both sub-networks and converted to boundaries
respectively to the sub-network they are placed.
3.4 Border Cut Conditions 11
BCC 1
The two cut sections (down and up) must be neighbors. If the two given sections
are not neighbors, then the input is invalid since there is no way of telling where to
perform the cut.
BCC 2
The up- and down sections must not already be boundaries.
BCC 3
The two sections (down and up) must not be in the same elementary route. Therefore,
the down section must contain an up marker board, and the up section must contain
a down marker board. Where up and down are the directions they face.
BCC 4
The sections up and down must not be reachable to each other if disconnected. In
that case, a cut will not result in two networks. Figure 3.5 shows a cut representing
this case, here, a cut will disconnect t4 and t5, but the other branch will make the
all sections still reachable - making the cut invalid (not well-formed).
Cut 1
mb4 mb6
t4 t5
mb5 mb7
mb2 mb8 mb10 mb12 mb14
b1 t2 t3 t6 t7 t8 t9 b10
mb1 mb3 mb9 mb11 mb13
Figure 3.5: An invalid cut. The result will be two not well-formed sub-networks since
all sections are still reachable.
12 3 Analysis
SC 1
This condition checks for overlap requirements. The overlap buffer must not be less
than the minimum safety distance. If any overlap section exists, it must reside in the
generated interlocking table or the sub-network it was based on.
SC 2
This condition checks if the points in the routes only reside in the same interlocking
table or the sub-network it was based on.
SC 3
This condition checks if the marker boards in the routes only resides in the generated
interlocking table or the sub-network it was based on.
SC 4
This condition checks if the conflicts in routes are independent. All conflicting routes
must reside in the same interlocking table.
3.6 Decomposition Methods 13
The rest of the section goes through decomposition methods that can solve the
problems in these scenarios.
Cut
b1 t2 t3 b4
The single cut decomposition method generates the sub-networks down and up which
can be seen in Figure 3.7.
b1 t2 t3 t2 t3 b4
(a) Down network. (b) Up network.
A station B station
t25 t26 t27 t28
A station B station
t25 t26 t27 t26 t27 t28
A single cut may, later on, be extended with new cut types other than border
cut. This can enable the user to use this decomposition method in different scenarios
opposed to only being restricted to scenario 2. This topic is further analyzed in
Section 3.7.
3.6 Decomposition Methods 15
Cluster Cut
Cut 1
t4 t5
b1 t2 t3 t6 t7 t8 t9 b10
Cut 2
The cluster cut decomposition method generates the sub-networks down and up
which can be seen in Figure 3.11.
t4
t4 t5
t5
b1 t2 t3 t6 t7
t6 t7 t8 t9 b10
As it can be seen the cluster cut is applicable for the scenario 3 and just like single
cut, it can also be applied between stations. Figure 3.12 shows an example of this,
station A and station B is connected by two parallel linears sections that are running
side-by-side.
16 3 Analysis
Cut 1
A station B station
t35 t36 t37 t38
Cut 2
A station B station
t35 t36 t37 t36 t37 t38
(a) Down network containing station A. (b) Down network containing station B.
Cluster Cut
Single Cut t5 t6
b1 t2 t3 t4 t7 t8 t9 t10 b11
b1 t2 t3
(a) N1 network.
t5 t6
t2 t3 t4 t7 t8
(b) N2 network.
t4 t5
t6 t7 t8 t9 b10
(c) N3 network.
Figure 3.15: The three sub-networks resulted by a multi cut decomposition method.
Linear Cut
Linear cut is introduced in the paper [8] and is similar to border cut. It is used
when the routes of the two sub-models partially overlap. The linear cut needs only
one linear section in common for the sub-networks down and up, while a border cut
needs two. Sometimes there are simply not enough linear sections between stations
to apply a border cut. Linear cut is a good solution for these cases, e.g. scenario
1. Figure 3.16 shows a case where a linear cut is applicable. T2 can be specified as
the cut specification. A cut here will add new boundaries to the T2 section. Marker
boards will also be added to ensure sane boundaries.
18 3 Analysis
A station B station
P2 T2 T3
Figure 3.16: The linear section T2 is connected to two stations through P2 and T3.
A station B station
P2 T2 T2 T3
Horizontal cut
Horizontal cut is another cut that is under development and is introduced in the paper
[4]. It will be capable of cutting between two minus ends of points, thus targeting
scenario 5. How it does this is best explained with an example. Figure 3.19 is based
on a figure from the paper regarding this particular cut. A horizontal cut is performed
on the shown red line, crossing the link between t9 and t10. To each of the two
sub-networks, above the cut and below it, two consecutive linear section is added on
the other side of the cut forming a stub. This abstracts the whole other sub-network.
The new sections have marker boards to satisfy the network conditions. The two
resulting sub-networks are shown in Figures 3.20 and 3.21. Notice that the high and
low names are used because down and up are reserved for network directions.
3.7 Other cut types 19
E8 E26
t13
T1 t7 t11 T16 T19
E1 E19
E10 E24
T3 t6 t9 T14 T17
E3 E15
E8 E26
t13
T1 t7 t11 T16 T19
E1 E19
E10 E24
T61 t62
E61
E52
T51 T52
E51
E12 E22
T3 t6 t9 T14 T17
E3 E15
Interlocking Types
The basic elements, sections, marker boards and routes are all given a unique id,
therefore an identifier is supplied for all of them.
Id = Text,
SecId = Id,
MbId = Id,
RouteId = Id
Network Layout
A network layout is represented as maps of linears, points and marker boards. Each
map contains identifiers as key values mapping to its element.
NetworkLayout ::
linears : SecId -m-> Linear
points : SecId -m-> Point
marker_boards : MbId -m-> MarkerBoard
Linear ::
neighbors : LinearEnd -m-> SecId
length : Distance
Where LinearEnd contains the direction of the neighbor and the Distance contains
the distance of the linear as a natural number.
LinearEnd = Direction,
Distance = Nat,
Direction == UP | DOWN
A point is also a record containing its neighbors and length. However its neighbors
are defined with PointEnd.
4.3 RSL Requirements 23
Point ::
neighbors : PointEnd -m-> SecId
length : Distance
Lastly, a marker board element is defined by which linear section it is mounted on,
which direction it is facing and its distance to the end of linear it is facing.
MarkerBoard ::
section : SecId
dir : LinearEnd
distance : Distance
Interlocking table
An interlocking table specifies the elementary routes for a specific network. See
Section 2.2.2 for more details about it. A route is specified as a short record definition
with all of the columns included.
Route ::
source : MbId
dest : MbId
path : SecId-list
overlap : SecId-list
points : SecId -m-> PointPos
signals : MbId-set
conflicts : RouteId-set,
InterlockingTable = RouteId -m-> Route
A record containing both the network layout and the interlocking table is simply
called an Interlocking.
Interlocking ::
track_layout : L.NetworkLayout
interlocking_table : InterlockingTable
Cut Types
The border cut, presented in Chapter 3, can be defined given two sections.
BorderCut ::
section_down:SecId
section_up:SecId
A single cut specification can be defined by the cut it executes. If more cuts have to
be included, then single cut has to be extended. Section 5.8 shows an example of this.
SingleCut = BorderCut
ClusterCut = SingleCut-set,
Where a cut element in the set is either a cluster cut or a single cut.
Cut == Cut_from_SingleCut(cut_to_singlecut: SingleCut) |
Cut_from_ClusterCut(cut_to_cluster: ClusterCut)
1. The union of ndown (sub-network down) and nup (sub-network up) elements
must be the same elements from n (Original network).
dom n_down_linears union dom n_up_linears = dom n_linears /\
dom n_down_points union dom n_up_points = dom n_points /\
dom n_down_markerboards union dom n_up_markerboards = dom n_markerboards /\
n_linears = C.ITG.I.L.linears(n),
n_points = C.ITG.I.L.points(n),
n_markerboards = C.ITG.I.L.marker_boards(n),
n_down_linears = C.ITG.I.L.linears(n_down),
n_down_points = C.ITG.I.L.points(n_down),
n_down_markerboards = C.ITG.I.L.marker_boards(n_down),
n_up_linears = C.ITG.I.L.linears(n_up),
n_up_points = C.ITG.I.L.points(n_up),
n_up_markerboards = C.ITG.I.L.marker_boards(n_up)
The prefixes in the listings such as C.ITG.I.L are used to access modules and
are described in Chapter 5.
2. The intersection of ndown and nup elements must yield the linears from the
cut specification and the marker boards placed on them. The marker boards
facing the boundary sides are not included because they are removed in the
decomposition process. The intersection of points must not result in any elements.
dom n_down_linears inter dom n_up_linears = {l_down, l_up} /\
dom n_down_markerboards inter dom n_up_markerboards =
{C.ITG.I.L.signals(l_down,n)(UP), C.ITG.I.L.signals(l_up,n)(DOWN)} /\
dom n_down_points inter dom n_up_points = {} /\
3. All elements in ndown must be the very same elements in n, except l_up which
is the new boundary.
(all l:SecId :- l isin n_down_linears \ {l_up} => n_down_linears(l) = n_linears(l)) /\
(all p:SecId :- p isin C.ITG.I.L.points(n_down) =>
C.ITG.I.L.points(n_down)(p) = C.ITG.I.L.points(n)(p)) /\
(all mb:SecId :- mb isin C.ITG.I.L.marker_boards(n_down) =>
C.ITG.I.L.marker_boards(n_down)(mb) = C.ITG.I.L.marker_boards(n)(mb)) /\
4. For the new boundary l_up at ndown , the following must hold.
UP ~isin C.ITG.I.L.signals(l_up,n_down) /\
UP ~isin C.ITG.I.L.neighbors(n_down_linears(l_up)) /\
C.ITG.I.L.neighbors(n_down_linears(l_up))(DOWN) =
C.ITG.I.L.neighbors(n_linears(l_up))(DOWN) /\
C.ITG.I.L.length(n_down_linears(l_up)) = C.ITG.I.L.length(n_linears(l_up)) /\
The up neighbor and the marker board mounted at UP must no longer exist. The
length and neighboring properties of l_up in n_down must match the properties
of l_up in n.
5. All elements in nup must be the very same elements in n, except l_down which
is the new boundary.
(all l:SecId :- l isin n_up_linears \ {l_down} => n_up_linears(l) = n_linears(l)) /\
(all p:SecId :- p isin C.ITG.I.L.points(n_up) =>
C.ITG.I.L.points(n_up)(p) = C.ITG.I.L.points(n)(p)) /\
(all mb:SecId :- mb isin C.ITG.I.L.marker_boards(n_up) =>
C.ITG.I.L.marker_boards(n_up)(mb) = C.ITG.I.L.marker_boards(n)(mb)) /\
6. For the new boundary l_down at nup , the following must hold.
26 4 Requirements
The down neighbor and the marker board mounted at DOWN must no longer exists.
The length and neighboring properties of l_down must match the properties of
l_down in n.
7. Finally, the sub-networks must be well-formed.
D.ITG.I.L.is_wf(n_down) /\ D.ITG.I.L.is_wf(n_up)
The cluster cut post-conditions are basically the same as single cut requirements,
the difference lies in the amount of single cuts that has to be checked. The requirements
are the following:
1. The union of ndown and nup must have the same elements as n.
dom n_down_linears union dom n_up_linears = dom n_linears /\
dom n_down_points union dom n_up_points = dom n_points /\
dom n_down_markerboards union dom n_up_markerboards = dom n_markerboards /\
3. The elements in ndown must be the very same elements in n as for the single
cut, except l_ups which is the set of new boundaries.
(all l:SecId :- l isin n_down_linears \ l_ups =>
n_down_linears(l) = n_linears(l)) /\
(all p:SecId :- p isin C.ITG.I.L.points(n_down) =>
C.ITG.I.L.points(n_down)(p) = C.ITG.I.L.points(n)(p)) /\
(all mb:SecId :- mb isin C.ITG.I.L.marker_boards(n_down) =>
C.ITG.I.L.marker_boards(n_down)(mb) = C.ITG.I.L.marker_boards(n)(mb)) /\
4. For the new boundaries l_ups at ndown , the same requirements from single cut
must hold.
(all l_up: SecId :- l_up isin l_ups =>
UP ~isin C.ITG.I.L.signals(l_up,n_down)) /\
(all l_up: SecId :- l_up isin l_ups =>
UP ~isin C.ITG.I.L.neighbors(n_down_linears(l_up))) /\
(all l_up: SecId :- l_up isin l_ups =>
C.ITG.I.L.neighbors(n_down_linears(l_up))(DOWN) =
C.ITG.I.L.neighbors(n_linears(l_up))(DOWN)) /\
(all l_up: SecId :- l_up isin l_ups =>
C.ITG.I.L.length(n_down_linears(l_up)) = C.ITG.I.L.length(n_linears(l_up))) /\
5. The elements in nup must be the very same elements in n, except l_downs which
is the set of new boundaries.
(all l:SecId :- l isin n_up_linears \ l_downs =>
n_up_linears(l) = n_linears(l)) /\
(all p:SecId :- p isin C.ITG.I.L.points(n_up) =>
C.ITG.I.L.points(n_up)(p) = C.ITG.I.L.points(n)(p)) /\
(all mb:SecId :- mb isin C.ITG.I.L.marker_boards(n_up) =>
C.ITG.I.L.marker_boards(n_up)(mb) = C.ITG.I.L.marker_boards(n)(mb)) /\
6. For the new boundaries l_ups at ndown , the same requirements from single cut
must hold.
(all l_down: SecId :- l_down isin l_downs =>
DOWN ~isin C.ITG.I.L.signals(l_down,n_up)) /\
(all l_down: SecId :- l_down isin l_downs =>
DOWN ~isin C.ITG.I.L.neighbors(n_up_linears(l_down))) /\
(all l_down: SecId :- l_down isin l_downs =>
C.ITG.I.L.neighbors(n_up_linears(l_down))(UP) =
C.ITG.I.L.neighbors(n_linears(l_down))(UP)) /\
(all l_down: SecId :- l_down isin l_downs =>
C.ITG.I.L.length(n_up_linears(l_down)) = C.ITG.I.L.length(n_linears(l_down))) /\
1. The network and the cut specifications in the set must all be well-formed.
pre C.ITG.I.L.is_wf(n) /\ C.cuts_wf(n, mc)
The function inherits the same requirements as single- and cluster cuts. It simply uses
the relevant post function depending on the cut type.
Interlocking
Network
Decomposition Table Interlocking
Layout
Generator
The assigned prefix names associated with each module can be seen below, they
appear frequently in the RSL code listings when accessing types in objects.
30 5 Design
Decomposition_THEOREM Decomposition_REQ
C-01 Linear section up from the cut specification exists in the network.
C-02 Linear section down from the cut specification exists in the network.
The last check disconnects the cut section such that they are no longer neighbors,
then l_up is checked if it is reachable in the down network and vice versa. In a
decomposition, the cut sections are disconnected with the sections around them and
not between them as it is done here (see Section 3.3). This does however not affect
the reachability check because this approach is only one single linear section away
from where the actual disconnection happens.
32 5 Design
This, however, is not possible due to the last check is done by the BCC function.
The reachability check to be precise. The problem is that the sub-networks should
only be unreachable after all of the single cuts in a cluster cut are disconnected. To
solve this problem a new BCC function in RSL is explicitly designed for cluster cut.
Here the network is disconnected in all given single cut locations, then the reachability
is checked. It could be argued that the reachability could be checked only for the last
single cut, but that could potentially exclude some not well-formed cuts. The RSL
specification can be seen below.
The multi cut theorem does the same checks, but it uses pattern matching to distinguish
between the cuts.
[MultiCut_decompose_post] in Decomposition_DESIGN |-
all n: C.ITG.I.L.NetworkLayout,
mc: C.MultiCut:-
(all c:C.Cut :- c isin mc =>
case c of
C.Cut_from_SingleCut(sc) ->
(all (n1,n2): C.ITG.I.L.NetworkLayout >< C.ITG.I.L.NetworkLayout
,→ :- (n1,n2) = decompose(n,sc) =>
C.ITG.I.L.is_wf(n1) /\ C.ITG.I.L.is_wf(n2) /\
C.SC2(n,n1,n2) /\ C.SC3(n,n1,n2) /\
C.SC4(n,n1,n2) /\ C.SC5(n,n1,n2)),
C.Cut_from_ClusterCut(cc)->
(all (n1,n2): C.ITG.I.L.NetworkLayout >< C.ITG.I.L.NetworkLayout
,→ :- (n1,n2) = decompose(n,cc) =>
C.ITG.I.L.is_wf(n1) /\ C.ITG.I.L.is_wf(n2) /\
C.SC2(n,n1,n2) /\ C.SC3(n,n1,n2) /\
C.SC4(n,n1,n2) /\ C.SC5(n,n1,n2))
end
)
end
Before showing the actual RSL specification for the soundness checks, a recap of the
conditions are listed.
SC1 If any overlap section exists in the route, it must reside in the generated
interlocking table or the sub-network it was based on.
SC2 Any point in the route must only reside in the same interlocking table or the
sub-network it was based on.
SC3 Any marker boards in the route must only reside in the generated interlocking
table or the sub-network it was based on.
SC4 All conflicting routes must reside in the same interlocking table.
The specification for SC1 can be seen on the next page. The function takes the
original network and the sub-networks as input. An interlocking table is generated
from the original network and this table is divided into two sub-tables. One table with
routes belonging to down and one table with routes belonging to up. The function
iterates all of the routes in down table and checks if all found overlaps are part of the
sub-network it is based on. The same is done for the down table.
5.4 Decomposition Specifications 35
The same exact procedure is applied for other soundness checks too, they are therefore
not shown here, except for SCC2. The SCC2 is listed for comparison, so the reader
can see how similar the check is performed. The rest of the soundness condition
definitions can be seen in Appendix E.
It receives the cut specification and then calls the apply_bc function followed by
get_reachableNetwork.
The apply_bc function is called twice for each sub-network to be generated. It
receives the direction (DOWN/UP) for targeted sub-networks (down/up) and the cut
specification as input. apply_bc has subroutines which perform the specific operations
defined for a border cut. After it has executed, both sub-networks are in a not
well-formed state, that is because they still contain both sides of the cut.
The get_reachableNetwork function is used to extract only the targeted sub-
network after the cut operations are performed by apply_bc. It requires an input of
a section that resides in the targeted sub-network. The extracted sub-network will be
well-formed if the cut is applied properly.
n_down = C.get_reachableNetwork(cut_applied_down,l_down),
n_up = C.get_reachableNetwork(cut_applied_up,l_up)
in
(n_down,n_up)
end
pre C.ITG.I.L.is_wf(n) /\ C.cut_wf(n,sc),
The decompose specification of cluster cut resembles the single cut specifica-
tion, but, there are some differences. The apply_bc function receives a cluster cut
as input which applies cut operations on all of the single cuts. Furthermore, the
get_reachableNetwork function receives arbitrary sections from the sets l_ups and
l_downs. As a side note, it does not matter which of the cut sections are used in
get_reachableNetwork, since they appear in both sub-networks, but for consistency,
the lower sub-network receives l_down and upper sub-network l_up.
Every time a cut is applicable for a network, the correct decompose function is
called, creating n1 and n2. The created sub-networks are then executed with the
rest of the remaining cuts. When no applicable cuts remain, the current network is
returned. The returned networks are assigned as ns1 and ns2. These networks are
38 5 Design
accumulated using the union operator. The union of all the returned sub-networks will
eventually be returned. This process can be visualized as a binary tree of networks
where only the leaves are included in the result, see Figure 5.3. It can also be seen
that a multi cut with n cuts will produce n+1 sub-networks.
N1 N2
N3 N6
N4 N5
Figure 5.3: Every child node in the tree represents a sub-network. The green leafs in
the binary tree identifies the final networks that are part of the multi-cut
decomposition result.
end
in
extra_mb_removed_n
end,
The specification of apply_bc for cluster cut differs by recursively applying single cut
operations on the same network until no more cuts are left.
apply_cut : ITG.I.L.NetworkLayout >< ClusterCut >< Direction -~-> ITG.I.L.NetworkLayout
apply_cut(n,cc,d) is
if cc = {} then n else
let
sc = hd cc,
sc_subnet = apply_cut(n,sc,d)
in
apply_cut(sc_subnet,cc \ {sc},d)
end
end,
Reachable Network
The get_reachableNetwork is a function that discovers a network from a given
section. It returns the discovered network as a NetworkLayout. This function is useful
and is applied in different scenarios. The function is specified as follow:
get_reachableNetwork : ITG.I.L.NetworkLayout >< SecId -~-> ITG.I.L.NetworkLayout
get_reachableNetwork(n,s) is
let
-- Get all sections
sections = get_all_sections(n,{s},{}),
-- Get all linears from given sections
linears = get_all_linears(n,sections),
-- Get all points from given sections
points = get_all_points(n, sections),
-- Get all signals from given sections (signals only exists in linears)
signals = get_all_signals(n, sections)
in
-- Instantiate a new network layout
ITG.I.L.mk_NetworkLayout(linears,points,signals)
end
pre ITG.I.L.s_exists(s,n),
let
current = hd tv,
visited = {current} union v,
For this function, a general traversal algorithm is used which is based on Depth
First Search (DFS) and Breadth First Search (BFS) [3]. Every section is discovered by
looking at the neighbors of the current one. The algorithm traverses in all directions,
it has the inputs (n, tv, v), where n is the network, tv is the set of nodes to be visited
and v is the set of visited sections. Both tv and v are of type SecId-set. Using sets
means that the next node to visit is arbitrary, so the algorithm does not exactly follow
DFS or BFS. That does however not matter since all of the nodes must be visited
anyway, in which order it happens, affect neither the result nor the performance. The
algorithm is finished when no more unvisited nodes exist (when tv is empty), in this
case, v is returned.
The start section given to the algorithm does not matter as long as it resides in
the correct sub-network to be discovered. A benefit of this algorithm is that we can
be sure all nodes are only visited once.
Disconnecting a Network
This specification function takes two neighbor sections and disconnects them. The
disconnections happen on both sections, meaning that both sections will no longer
have the other one as a neighbor. Since there exist two types of sections (linears and
points), the function must be able to cover all combinations. If one of the sections is
a point, then the correct point-end must be determined to disconnect properly. The
specification of get_disconnectedNetwork can be seen in the listing below.
linearsToDisconnect =
-- if down section is a linear
[ l +> remove_nb(ITG.I.L.get_linear(l,n), UP) | l:SecId :- l isin
,→ ITG.I.L.linears(n) /\ l = secIdDown] !!
-- if up section is a linear
[ l +> remove_nb(ITG.I.L.get_linear(l,n), DOWN) | l:SecId :- l isin
,→ ITG.I.L.linears(n) /\ l = secIdUp],
pointsToDisconnect =
-- if down section is a point
-- point end to disconnect: ITG.I.L.get_p_end_by_nb_id(s,s,n)
5.4 Decomposition Specifications 41
[ p +> remove_nb(ITG.I.L.get_point(secIdDown,n),
,→ ITG.I.L.get_p_end_by_nb_id(secIdDown, secIdUp, n)) | p:SecId :- p isin
,→ ITG.I.L.points(n) /\ p = secIdDown] !!
-- if up section is a linear
[ p +> remove_nb(ITG.I.L.get_point(secIdUp,n),
,→ ITG.I.L.get_p_end_by_nb_id(secIdUp, secIdDown, n)) | p:SecId :- p isin
,→ ITG.I.L.points(n) /\ p = secIdUp]
in
-- Update the network by adding the new boundaries
ITG.I.L.mk_NetworkLayout(linears !! linearsToDisconnect, points !!
,→ pointsToDisconnect, ITG.I.L.marker_boards(n))
end
pre ITG.I.L.are_neighbors(secIdDown, secIdUp, n),
Another version explicitly for cluster cut is defined that reuses the already defined
get_disconnectedNetwork for a single cut. This version visits all single cuts and
disconnects between the cut section one by one. The returned network will probably
be disconnected multiple places.
The id attribute is the section identifier that already exists in the network layout.
The side attribute is used to define l_down and l_up from the specification. The
type of the sections are also included, even though only linears sections are currently
allowed, it may be beneficial for new cut types in the future to have this attribute.
A cluster cut can be defined using the clusterCut tag. Inside the cluster cut tag,
there can be any arbitrary number of border cut definitions. The identifiers of border
cuts are used to distinguish between them.
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.4.1" xmlns:xmi="http://www.omg.org/spec/XMI/2.4.1">
<xmi:Documentation exporter="DK-IXL" exporterVersion="0.1"/>
<clusterCut id="miniClusterCut">
<borderCut id="miniBorderCut">
<trackSection id="b10" side="down" type="linear"/>
<trackSection id="t10" side="up" type="linear"/>
</borderCut>
</clusterCut>
</xmi:XMI>
A multi cut is defined with the multiCut tag. Inside the tag, there can be any
number of single and cluster cuts. The following listing shows an example.
</borderCut>
<borderCut id="CC_BorderCut2">
<trackSection id="t20" side="down" type="linear"/>
<trackSection id="t21" side="up" type="linear"/>
</borderCut>
</clusterCut>
</multiCut>
</xmi:XMI>
In the given example, the multi cut contains one border cut (single cut) and one cluster
cut. The cluster cut contains two additional border cuts. Both cuts (BorderCut1
and ClusterCut1) produces each two sub-networks, so we can expect to produce 3
sub-networks in total when decomposing consecutively.
44 5 Design
Cut
SingleCut
# type
+ Cut()
+ SingleCut()
+ getCutType()
+ isA()
MultiCut
- borderCuts
- clusterCuts
BorderCut
ClusterCut
+ MultiCut()
- linear_up
- borderCuts + getBorderCuts()
- linear_down
+ getClusterCuts()
+ BorderCut() * + ClusterCut() * + getBorderCut()
+ getLinearUp() + getBorderCuts() + getClusterCut()
+ getLinearDown() + setBorderCuts() + getCut()
+ setLinearUp() * + setBorderCuts()
+ setLinearDown() + setClusterCuts()
Cut
SingleCut
# type
+ Cut()
+ SingleCut()
+ getCutType()
+ isA()
MultiCut
- borderCuts
- clusterCuts
BorderCut
ClusterCut
+ MultiCut()
- linear_up
- borderCuts + getBorderCuts()
- linear_down
+ getClusterCuts()
+ BorderCut() * + ClusterCut() * + getBorderCut()
+ getLinearUp() + getBorderCuts() + getClusterCut()
+ getLinearDown() + setBorderCuts() + getCut()
+ setLinearUp() * + setBorderCuts()
+ setLinearDown() + setClusterCuts()
*
+ BorderCutParser() * + ClusterCutParser() +
+
MultiCutParser()
~MultiCutParser()
+ ~BorderCutParser() + ~ClusterCutParser()
+ getBorderCut() + getClusterCut() + getMultiCut()
+ parse() + parse() + parse()
+ print_element_names() + print_element_names() + print_element_names()
+ doVisit() + doVisit() + doVisit()
+ getSearchIndicator() + getSearchIndicator() + getSearchIndicator()
+ getSearchValue() + getSearchValue() + getSearchValue()
*
5.6.3 Domain
Finally, all of the classes are shown in Figure 5.6. This figure can be interpreted as
the domain model. The relationship between the main decomposition classes and the
other classes are introduced. The already showed relationships in previous diagrams
are not included this time for simplicity.
The class Decomposition is the main class used to trigger the decomposition process
and the class DecompositionCommon contains commonly used functions by other
classes, which is why it is associated with them all.
DecompositionXmlWriter
+ DecompositionXmlWriter()
+ xmlWriteMainDoc() MultiCut
- xmlWriteIxl() - borderCuts
- xmlWriteCut()
- clusterCuts
- xmlWriteNetwork()
- xmlWriteRouteTable() + MultiCut()
- xmlWriteNeighbor() + getBorderCuts()
- xmlWriteRouteConditions() + getClusterCuts()
MultiCutParser + getBorderCut()
+ getClusterCut()
+ getCut()
+ MultiCutParser() + setBorderCuts()
+ ~MultiCutParser() + setClusterCuts()
+ getMultiCut() DecompositionCommon
Decomposition
+ parse()
+ print_element_names() - interlocking
+ doVisit() + DecompositionCommon() - networkLayout
+ getSearchIndicator() + isCut_wf() - routeTable
+ getSearchValue() + isCut_wf() -common + Decomposition()
+ isCuts_wf()
+ decompose()
ClusterCutParser + sectionExists()
+ decompose()
+ cutSectionsExistsInNetwork()
+ decompose()
+ cutSectionsExistsInNetwork()
+ setInterlocking()
+ apply_bc()
+ setNetworkLayout()
+ ClusterCutParser() + apply_bc()
ClusterCut + setRouteTable()
+ ~ClusterCutParser() + apply_bc() + toDescription()
+ getClusterCut() and 23 more...
- borderCuts + printStats()
+ parse()
+ print_element_names() + ClusterCut()
+ doVisit() + getBorderCuts()
+ getSearchIndicator() + setBorderCuts()
+ getSearchValue()
BorderCutParser BorderCut
- linear_up
- linear_down
+ BorderCutParser()
+ ~BorderCutParser() + BorderCut()
+ getBorderCut() + getLinearUp()
+ parse() + getLinearDown()
+ print_element_names() + setLinearUp()
+ doVisit() + setLinearDown()
+ getSearchIndicator()
+ getSearchValue()
The parser in Figure 5.7 shows the sequence diagram of the border cut. The parser
instance starts by calling the cutparser with the cut file path as the argument. The
cutparser then calls the borderCutParser with the XML node identified from the
borderCut tag. The borderCutParser will then create a new border cut object that
it will populate with its properties. The result will then be returned all the way back
to the parser object.
The DecompositionParser in the sequence diagram does also call the parser for
network layout, which is how it differentiates from CutParser. The parsing of the
network layout is omitted since it is not developed in this project. Notice that the
cut name and its type is generalized in the last return value. This is possible because
of the inheritance scheme used for the cuts (see Figure 5.4), a derived cut type can
be cast to its base class and vice versa. Casting to another cut type is however not
possible.
48 5 Design
The Figure 5.8 shows a sequence diagram of the cluster cut parsing. The initial steps
are the same until clusterCutParser is called. The clusterCutParser instance
contains a loop that visits all XML nodes starting from the given pcurr:XmlNodePtr.
If a border tag occurs, then a BorderCutParser is created and called with parse
method. It can be seen from the previous sequence diagram that a bordercut object
will be returned from the BorderCutParser. The loop stop until no more XML nodes
exist. Finally, a ClusterCut object is created which is populated with found border
cuts. The cluster cut object is then returned all the way back to the parser object.
The last parser sequence to examine is the multi cut parser which can be seen in
Figure 5.9. The multi cut resembles the cluster cut parser sequence but is slightly
more complex. The sequence shows how the multi cut parser can exploit the already
defined parsers for border cut and cluster cut. The multiCutParser contains a big
for loop block that checks for border cuts and cluster cuts in the given XML file. Any
occurrence creates the respective parser for the found cut type. The received objects
from the parsers are saved into a new MultiCut object, which is the returned object
to the initial caller.
of the main class which will be executable. It starts by calling the decomposition
instance with a network and a single cut as arguments. The decomposition instance
will create two new instances of the network (downNetwork and upNetwork) using
the clone function defined in common (see Section 6.4). Thereafter will both net-
5.7 Sequence Diagrams 51
works be modified by the apply_bc method that will disconnect sections and remove
unnecessary marker boards at a cut position. The networks are then respectively
rediscovered using reachableNetwork before returning the results back to the main
object.
The next sequence diagram in Figure 5.11 shows the cluster cut decomposition. It
resembles very much single cut decomposition, but the apply_bc method in this cases
triggers a loop that will call the apply_bc for all the single cuts. The downNetwork
and upNetwork will be altered multiple times before called back to the main object.
Notice that apply_bc is an overloaded function that differs by its input arguments.
Finally, the sequence diagram for a multi cut is shown in Figure 5.12. This diagram
is simplified by referencing the previous sequences with the frames sd single cut
and sd cluster cut. Notice that the referenced frames can call objects not shown
in this figure, such as the DecompositionCommon. Even though the sequence is
simplified, it still has a complex flow. This can be observed by the recursive calls.
The algorithm here is based on the specification in Section 5.4.3. The decompose
function in decomposition starts by finding applicable cuts. If no applicable cuts
exist, then none of the code in opt frame is executed. If applicable cuts exist, then a
decomposition sequence is executed depending on the cut type. The same decompose
function is called again for the created sub-networks ns.down and ns.up. Eventually,
when no more cuts exist, all of the networks are returned as a result to the main
object.
5.8.1 Specifications
1. Specify the requirements of linear cut in RSL.
2. Create RSL specification for cut.
a) Introduce the new cut:
LinearCut ::
section:SecId,
The given direction to add a new cut assumes that the nature of the cut does
not deviate extremely from the already defined border cut. In that case, additional
development of the tool might be necessary. The advantage of the decomposition
methods single-, cluster- and multi cut, is that they can still be applicable for different
cut types. A cluster cut or a multi cut consisting of different cut types will provide a
huge flexibility.
54
CHAPTER 6
Implementation & Tests
This chapter makes a run-through of the implementation of the decomposition tool.
Unlike previous chapter (Chapter 5), this chapter focuses not on the overall structure
but technical challenges unique to this project.
[rr-project]/decomposers/networkDecomposition/
Where [rr-project] is the main project folder of RobustRailS tools. The main
decomposition classes such as main.cpp and Decomposition.cpp are placed in this
folder, including the executables. The rest of the files are in the sub-folders:
[rr-project]/dkixl/
[rr-project]/parsers/ixlparser/
56 6 Implementation & Tests
The dkixl folder contains the interlocking classes and the ixlparser folder
contains the interlocking parser classes. The other included folders and codes will not
be listed since they are irrelevant.
6.2 Parser
The libxml2 library is used in the implementation of the cut parser. This new
parser extension is based on the already existing parser for the network layouts from
verification tool [13]. The basic idea behind implementing the parser is to visit every
XML node and save the appropriate attributes in found occurrences. The nodes
represent the tags in the XML tree created by the libxml2 library. The challenge in
this part of the project was to understand the already defined parsers and extend
accordingly.
DecompositionCommon
::clone
DecompositionCommon
::setLinearRelations
DecompositionCommon
::getSection
DecompositionCommon DecompositionCommon
::clone ::setPointRelations
DecompositionCommon
::setMarkerBoardRelations
DecompositionCommon
::setLevelCrossingRelations
6.5 Tests
Test driven development (TDD) methodology has been used in this project during the
development of the tool. This methodology requires the test cases to be established
before the code is written. Testing new functions in small cycles ensure that the
written specification and the C++ code works as expected. The test cases are written
in the form of unit tests. Every test contains assertions that must be true for successful
a test case. Another advantage that the tests bring is the confidence in the written
code. After a change in the code, one can simply run all the tests to see if all the
cases are still covered.
[get_disconnectNetwork_with_points]
let n = D.C.get_disconnectedNetwork(mini_ext, "t3", "t4") in
D.C.ITG.I.L.are_neighbors("t3", "t4", mini_ext) /\
D.C.ITG.I.L.are_neighbors("t3", "t4", n) = false
end
-- sml result
[get_disconnectNetwork_with_points] true
The next test relies on the result of the first shown test and extends it by performing
a get_reachableNetwork function on the disconnected network.
[get_reachableNetwork]
let n = D.C.get_disconnectedNetwork(mini_ext, D.C.section_down(sc1),
,→ D.C.section_up(sc1)) in
D.C.get_reachableNetwork(mini_ext, "b1") ~=
D.C.get_reachableNetwork(n, "b1")
end,
-- sml result
[get_reachableNetwork] true
The test below is an example of a test with an expected value of false. A set of non-
applicable cuts are given to the function get_applicableCuts which will therefore
return an empty set.
6.5 Tests 59
[get_applicableCuts_False]
let cuts = D.C.get_applicableCuts(mini_ext, mc2) in
(cuts ~= {}) = false
end,
-- sml result
[get_applicableCuts_False] true
The RSL listing below contains a test for the multi cut decomposition method. A valid
multi cut is given to the decompose function which generates well-formed sub-networks.
[decomposed_mc1_wf]
let ns = D.decompose(mini_ext, mc1, true) in
(all n : D.C.ITG.I.L.NetworkLayout :- n isin ns => D.C.ITG.I.L.is_wf(n))
end
-- sml result
[decomposed_mc1_wf] true
The conversion to sml makes it possible to see the results in other constructions than
true/false assertions. The test below prints out the sub-networks after a multi cut
decomposition.
[decompose_mc1]
D.C.decomposed_sec_repr(D.decompose(mini_ext, mc1, true), {}),
-- sml result
[decompose_mc1] {{"t2","t3","b1"},{"t2","t8","t7","t6","t5","t3","t4"},
{"t11","b12","t10"},{"t7","t8","t5","t6","t11","t10","t9"}}
SECTION("Down"){
sectionsToVisit.push("t2");
std::set<std::string> sections_down =
common -> getReachableSections(network, sectionsToVisit,
,→ visited);
REQUIRE(sections_down.size() == 2);
}
SECTION("Up"){
sectionsToVisit.push("t3");
std::set<std::string> sections_up =
common -> getReachableSections(network, sectionsToVisit,
,→ visited);
REQUIRE(sections_up.size() == 10);
}
}
}
}
The result of the tests are obtained by creating an executable and running it, a list of
successful and unsuccessful assertions are printed. An example of one of the assertion
output is shown below.
PASSED:
REQUIRE( sections_up.size() == 10 )
with expansion:
10 == 10
The overall result of the tests is also obtained. The result is:
can be applied. However, {t5,t6} and {t7,t8} must be applied as a cluster cut to
output valid sub-networks. A multi cut is defined as seen below which will enable us
to generate all of the sub-networks in one go.
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.4.1" xmlns:xmi="http://www.omg.org/spec/XMI/2.4.1">
<xmi:Documentation exporter="DK-IXL" exporterVersion="0.1"/>
<multiCut id="miniEMultiCut">
<clusterCut id="miniEClusterCut1">
<borderCut id="miniEClusterCut1_BC1">
<trackSection id="t5" side="down" type="linear"/>
<trackSection id="t6" side="up" type="linear"/>
</borderCut>
<borderCut id="miniEClusterCut1_BC2">
<trackSection id="t7" side="down" type="linear"/>
<trackSection id="t8" side="up" type="linear"/>
</borderCut>
</clusterCut>
<borderCut id="miniRBorderCut1">
<trackSection id="t2" side="down" type="linear"/>
<trackSection id="t3" side="up" type="linear"/>
</borderCut>
<borderCut id="miniBorderCut2">
<trackSection id="t10" side="down" type="linear"/>
<trackSection id="t11" side="up" type="linear"/>
</borderCut>
</multiCut>
</xmi:XMI>
mb8 mb10
t5 t6
mb4 mb6 mb12 mb7 mb14 mb9 mb16 mb18 mb20
t5 t6
mb6 mb12 mb7 mb14
b1 t2 t3
t2 t3 t4 t7 t8
mb1 mb3 mb3 mb5 mb11
By applying the multi cut, four sub-networks are successfully produced. The tool is
lightweight and the decomposition happens instantaneously. The full XML definitions
for the sub-networks can be seen in Appendix C and the Figures 7.2 to 7.5 show
sub-networks generated.
The verification tool successfully verified the safety properties for all of the networks.
Table 7.1 shows the verification metrics for the compositional analysis of the sub-
networks. The metrics for the compositional analysis are obtained by summing the
results from the sub-network metrics, except the memory usage, which is the maximum
memory usage of any verification.
The results show that the compositional verification of the network requires much
less memory than the monolithic run, only third in this case. The running time does
also show positive results, which is only 8.47 seconds opposed to the 25.31 seconds
in the monolithic run. The table shows the result for a synchronized run of the
compositional verification, if all of the sub-networks were to be executed concurrently,
then the memory usage would increase. In that case, the memory usage is 240.80 MB,
which is still less than the monolithic run.
Table 7.1: Comparison between monolithic and compositional execution of the verifi-
cation tool.
7.4 EDL
EDL stands for Early Deployment Line and is the first the first regional line in
Denmark to be commissioned in the Danish Signalling Programme. The line stretches
from Roskilde- to Næstved station and is 55km in total. The layout of the EDL line is
confidential and can therefore not be included in this paper. A compositional analysis
has already been done in the paper [7], where a manual decomposition was done by
hand.
64 7 Experiments
The same decomposition has been successfully replicated by the developed tool.
The existence of intermediate stations between Roskilde and Næstved adds up to eight
sub-networks. Where each sub-network is a station. The metrics from the paper are
shown here in Table 7.2. This table contains an extra row containing the state space
dimension (in logarithmic scale).
Table 7.2: Comparison between monolithic and compositional verification of the early
development line. Metrics are obtained from another machine.[7].
Another successful verification of safety properties of all the networks shows the
same picture. The compositional verification of the eight sub-networks shows that
the verification time is approximately a third of the monolithic analysis. The memory
usage of a synchronized run shows a maximum of 9393 MB, whereas a concurrent run
would result in 12363 MB. Both are significantly less than the 26484 MB used by the
monolithic analysis.
Table 7.3: Comparison between monolithic and compositional execution run time
before termination.
66
CHAPTER 8
Discussion
This chapter contains a discussion of the project and the developed tool. The results
of the experiments are recalled and discussed if the tool delivers what it promises.
The current limitations of the tool and the consequences it may possess are discussed.
Finally, potential improvements are presented that can be included in a future work
of the tool.
8.1 Results
Different networks have been used for experimental purposes. The tool did certainly
satisfy its main goal of decomposing all given networks. The self-created network mini-
e showed that it could be applied a border cut with different types of decomposition
methods, such as single-, cluster and multi cut. Successful decomposition was also
achieved with the EDL and Roskilde network. Both mini-e and EDL showed better
certifications metrics after the decomposition. A cluster cut decomposition of Roskilde,
however, was not enough to overcome the state explosion problem. The limited time
with this confidential network was not enough to find more than one applicable cut.
A multi cut specification with more cuts could have resulted in smaller sub-networks,
thus resulting in a successful verification. If other cut types other than border cut was
included in this tool, such as the linear cut and horizontal cut, then the possibility of
specifying such multi cut could have been easier.
The performance of the decomposition tool has been great, and all executions were
instantaneous. This is due to the tool being lightweight and developed in C++. The
user experience is smooth and easy. A non-technical user can easily learn the use of
the command line tool. The tool shows great potential to be used together with the
verification tool in the future.
8.2 Limitations
The tool does have some limitations that can be tedious in some cases. Some of them
are already mentioned in the paper. These limitations are:
• Limited cut types. Only border cut is included in this project. This may become
a limitation depending on the network that has to be decomposed.
• Code dependence. The tool uses a shared library from RobustRailS’ verification
project (see Appendix A). This is a limitation only if the tool will be kept separate
68 8 Discussion
from rest of the tool-chain. The shared library can influence the decomposition
tool if changed and recompiled.
• Not considered network elements. For simplicity, some elements of the network
layouts were not considered, such as level crossings.
• A Static checker. A static checker can be used ensure that the given- and
generated network is statically correct. Currently, the RobustRailS’ tool provides
this check for network inputs, however, manually running this tool for every
sub-network can be tedious.
• Automatic find of cuts. Develop an algorithm that searches for applicable cuts in
the network. A function as such will fully automate decomposition of networks
and free the user of manually defining cut specifications.
• Graphical user interface. A graphical user interface can make it easier for the
user to specify where to apply the cut. A good option here would be to integrate
the decomposition tool with the graphical tool developed by Andreas [5].
CHAPTER 9
Conclusion
The goal of this project was to support the RobustRailS’ compositional verification
by developing a decomposition tool. The verification tool suffered from the state
explosion problem that is seen with model-checkers. This made it difficult to verify
large networks.
The tool uses the cut type border cut with a variety of decomposition methods
such as single-, cluster- and multi cut. Network layouts and cut specifications in XML
format are used by the tool to generate the sub-networks. The sub-networks are writ-
ten as XML files to the file system which can be used together with the verification tool.
The tool has been tested using unit tests, and by experiments. The unit tests have
been solely used to test the functionalities of the tool. The experiments, however,
has been a combination of experimenting the decomposition- and verification tool.
Comparison between the monolithic and compositional verification reveals that the
decomposition tool can support the verification tool and potentially solve the state
explosion problem.
70
APPENDIX A
Installing the tool
A.1 Prerequisites
To be able to install/build the project, some libraries must first be installed. These
libraries are common to C++ and are often available through the default system
package manager by OS. In case the operating system is Ubuntu/Linux, the libraries
can be installed with:
It is important that the library versions are up to date and are the same during
the build and executions. When the libraries are updated, then the project must be
built again, otherwise it will look after older library versions which no longer exist.
Notice that only the folder decomposers, dkixl and parsers have been used in
development. All the other files and folders are dependencies.
72 A Installing the tool
A.2 Building
The project’s building process is handled by CMake. To build the project, do the
following in exact order:
Where [rr-project] is the root folder of the project. When a change is made to the
source code, rerunning make a single time should be sufficient.
B.2 Usage
To see the usage list simply run ./Decompose without any options or with the -h flag.
The user must be in the path of Decompose binary file.
Usage:
-h,--help Show this help message
-c,--cut Specify the cut file path
-n,--network Specify the network file path
If this message does not appear, then the tool was not properly installed. If it appears,
you may continue with the guide. Let us start with an example. Let us decompose a
network called mini-e. The XML definitions of the cut specification and the network
layout before and after the decomposition are included in the Appendix C.
The user must provide a relative path, both for the network layout and the cut
specification. The -n and -c options are used to accomplish this. The following
command is executed to decompose the mini-e network with singe cut:
If successful, the detected cut type and a list of generated XML files will be printed:
BorderCut Detected
Generated xml file: ./mini-e_down.xml
Generated xml file: ./mini-e_up.xml
Another example is shown below. To decompose the mini-e network with a multi
cut specification, the same command is executed but with a different cut path:
If successful, the detected cut type and a list of generated XML files will be printed:
MultiCut Detected
Generated xml file: ./xml/mini-e_mc_1.xml
Generated xml file: ./xml/mini-e_mc_2.xml
Generated xml file: ./xml/mini-e_mc_3.xml
Generated xml file: ./xml/mini-e_mc_4.xml
</borderCut>
</xmi:XMI>
C.2.2 mini-e_cc.xml
C.2.3 mini-e_mc.xml
C.3 Sub-networks
C.3.1 After Single Cut
mini-e_sc_down.xml
mini-e_sc_up.xml
mini-e_cc_down.xml
</xmi:XMI>
mini-e_cc_up.xml
mini-e_mc_2.xml
mini-e_mc_3.xml
mini-e_mc_4.xml
D.1 Decomposition_TEST
This file contains all of the RSL tests.
/*======================================================
* File: $Name: Decomposition_TEST.rsl $
* Created: $Date: 2017-04-10 15:16:14 $
* Author: $Author: Cebrail Erdogan<[email protected]>$
* Description: Test cases for decomposition of networks.
*=======================================================
*/
Decomposition_DESIGN
scheme Decomposition_TEST =
with T in
class
object D : Decomposition_DESIGN
value
/**
* Extended mini layout.
* The extended mini layout contains extra linear sections compared to the mini
,→ layout.
*
*
* t5 t6
* /-|-----|------|-\
* / \
* |-----|-----|-----|---/---|-----|------|---\--|------|------|------|
* b1 t2 t3 t4 t7 t8 t9 t10 t11 b12
*
*
*/
-- linears
b1 : D.C.ITG.I.L.Linear = D.C.ITG.I.L.mk_Linear([UP +> "t2"], 40),
t2 : D.C.ITG.I.L.Linear =
D.C.ITG.I.L.mk_Linear([DOWN +> "b1", UP +> "t3"], 100),
t3 : D.C.ITG.I.L.Linear =
D.C.ITG.I.L.mk_Linear([DOWN +> "t2", UP +> "t4"], 100),
t5 : D.C.ITG.I.L.Linear =
88 D Tests
-- points
t4 : D.C.ITG.I.L.Point =
D.C.ITG.I.L.mk_Point(
[NB_STEM +> "t3", NB_PLUS +> "t7", NB_MINUS +> "t5"], 100),
t9 : D.C.ITG.I.L.Point =
D.C.ITG.I.L.mk_Point(
[NB_STEM +> "t10", NB_PLUS +> "t8", NB_MINUS +> "t6"], 100),
-- all elements
all_linears : SecId -m-> D.C.ITG.I.L.Linear =
["b1" +> b1, "t2" +> t2, "t3" +> t3, "t5" +> t5, "t6" +> t6,
"t7" +> t7, "t8" +> t8, "t10" +> t10, "t11" +> t11, "b12" +> b12],
all_points : SecId -m-> D.C.ITG.I.L.Point = ["t4" +> t4, "t9" +> t9],
all_sigs : MbId -m-> D.C.ITG.I.L.MarkerBoard =
["mb1" +> mb1, "mb3" +> mb3, "mb4" +> mb4, "mb5" +> mb5,
"mb6" +> mb6, "mb7" +> mb7, "mb8" +> mb8, "mb9" +> mb9,
"mb10" +> mb10, "mb11" +> mb11, "mb12" +> mb12, "mb13" +> mb13, "mb14" +>
,→ mb14,
"mb15" +> mb15, "mb16" +> mb16, "mb17" +> mb17, "mb18" +> mb18, "mb20"
,→ +> mb20],
mini_ext : D.C.ITG.I.L.NetworkLayout =
D.C.ITG.I.L.mk_NetworkLayout(all_linears, all_points, all_sigs),
empty_n : D.C.ITG.I.L.NetworkLayout =
D.1 Decomposition_TEST 89
-- cut specs
sc1: D.C.SingleCut = D.C.mk_BorderCut("t2","t3"),
sc2: D.C.SingleCut = D.C.mk_BorderCut("t10","t11"),
sc3: D.C.SingleCut = D.C.mk_BorderCut("t5", "t6"),
sc4: D.C.SingleCut = D.C.mk_BorderCut("t7", "t8"),
sc5: D.C.SingleCut = D.C.mk_BorderCut("b1", "t2"), -- invalid
sc6: D.C.SingleCut = D.C.mk_BorderCut("t20", "t21"), -- invalid
sc7: D.C.SingleCut = D.C.mk_BorderCut("t30", "t31"), -- invalid
cc1: D.C.ClusterCut = {sc3,sc4},
cc2: D.C.ClusterCut = {sc2,sc4},
cut1: D.C.Cut = D.C.Cut_from_SingleCut(sc1),
cut2: D.C.Cut = D.C.Cut_from_SingleCut(sc2),
cut3: D.C.Cut = D.C.Cut_from_SingleCut(sc7),
cut4: D.C.Cut = D.C.Cut_from_ClusterCut(cc1),
mc1: D.C.MultiCut = {cut1,cut2},
mc2: D.C.MultiCut = {cut3} -- invalid
-- Variables used
test_case
[single_cut]
sc1,
[cluster_cut]
cc1,
[multi_cut]
mc1,
[mini_ext]
mini_ext
-- Well-formedness tests
test_case
[mini_ext_is_wf]
D.C.ITG.I.L.is_wf(mini_ext),
[sc_wf]
D.C.cut_wf(mini_ext, sc1),
[cc_wf]
D.C.cut_wf(mini_ext, cc1),
[mc_wf]
D.C.cuts_wf(mini_ext, mc1)
[remove_nb_up]
let s = D.C.remove_nb(t2, UP) in UP ~isin dom D.C.ITG.I.L.neighbors(s) end,
90 D Tests
[remove_nb_minus]
let s = D.C.remove_nb(t4, NB_MINUS) in NB_MINUS ~isin dom
,→ D.C.ITG.I.L.neighbors(s) end,
[remove_nb_plus]
let s = D.C.remove_nb(t4, NB_PLUS) in NB_PLUS ~isin dom
,→ D.C.ITG.I.L.neighbors(s) end,
[remove_nb_stem]
let s = D.C.remove_nb(t4, NB_STEM) in NB_STEM ~isin dom
,→ D.C.ITG.I.L.neighbors(s) end,
[isOverlapDistanceSatisfied_False]
D.C.isOverlapDistanceSatisfied(mb1,b1) = false,
[isOverlapDistanceSatisfied_True]
D.C.isOverlapDistanceSatisfied(mb1,t2)
-- Getters
test_case
[get_applicableCuts_True]
let cuts = D.C.get_applicableCuts(mini_ext, mc1) in
cuts = mc1
end,
[get_applicableCuts_False]
let cuts = D.C.get_applicableCuts(mini_ext, mc2) in
cuts = {}
end,
[get_all_section]
let ss = D.C.get_all_sections(mini_ext, {"b1"}, {}) in
card ss = card D.C.ITG.I.L.sections(mini_ext)
end,
[get_all_linears]
let ls = D.C.get_all_linears(mini_ext, D.C.ITG.I.L.sections(mini_ext)) in
ls = D.C.ITG.I.L.linears(mini_ext)
end,
[get_all_points]
let ps = D.C.get_all_points(mini_ext, D.C.ITG.I.L.sections(mini_ext)) in
ps = D.C.ITG.I.L.points(mini_ext)
end,
[get_all_signals]
let mbs = D.C.get_all_signals(mini_ext, D.C.ITG.I.L.sections(mini_ext)) in
mbs = D.C.ITG.I.L.marker_boards(mini_ext)
end,
[get_reachableNetwork]
let n = D.C.get_disconnectedNetwork(mini_ext, D.C.section_down(sc1),
,→ D.C.section_up(sc1)) in
D.C.get_reachableNetwork(mini_ext, "b1") ~=
D.C.get_reachableNetwork(n, "b1")
end,
D.1 Decomposition_TEST 91
[get_disconnectNetwork_sc1]
let n = D.C.get_disconnectedNetwork(mini_ext, D.C.section_down(sc1),
,→ D.C.section_up(sc1)) in
D.C.ITG.I.L.are_neighbors(D.C.section_down(sc1), D.C.section_up(sc1),
,→ mini_ext) /\
D.C.ITG.I.L.are_neighbors(D.C.section_down(sc1), D.C.section_up(sc1), n) =
,→ false
end
[decomposed_sc1]
D.C.decomposed_sec_repr(D.decompose(mini_ext, sc1)),
[decomposed_sc1_wf]
let (n1,n2) = D.decompose(mini_ext, sc1) in
D.C.ITG.I.L.is_wf(n1) /\ D.C.ITG.I.L.is_wf(n2)
end,
[decomposed_cc1]
D.C.decomposed_sec_repr(D.decompose(mini_ext, cc1)),
[decomposed_cc1_wf]
let (n1,n2) = D.decompose(mini_ext, cc1) in
D.C.ITG.I.L.is_wf(n1) /\ D.C.ITG.I.L.is_wf(n2)
end,
[decompose_mc1]
D.C.decomposed_sec_repr(D.decompose(mini_ext, mc1), {}),
[decomposed_mc1_wf]
let ns = D.decompose(mini_ext, mc1) in
(all n : D.C.ITG.I.L.NetworkLayout :- n isin ns => D.C.ITG.I.L.is_wf(n))
end,
[decomposed_cluster_cut_apply_cut]
D.C.apply_cut(mini_ext, cc1, DOWN)
-- BCC tests
-- Takes significant time to execute
test_case
[bcc1]
D.C.BCC1(mini_ext, sc1),
[bcc2_M]
D.C.BCC2_M(mini_ext, sc1),
[bcc2_T]
let (n_down,n_up) = D.decompose(mini_ext, sc1) in
D.C.BCC2_T(mini_ext, n_down, n_up)
end,
92 D Tests
[bcc3]
let (n_down,n_up) = D.decompose(mini_ext, sc1) in
D.C.BCC3(mini_ext, n_down, n_up)
end,
[bcc4]
let (n_down,n_up) = D.decompose(mini_ext, sc1) in
D.C.BCC4(mini_ext, n_down, n_up)
end,
[bcc5]
let (n_down,n_up) = D.decompose(mini_ext, sc1) in
D.C.BCC5(mini_ext, n_down, n_up)
end
end
[mini_ext_is_wf] true
[sc_wf] true
[cc_wf] true
[mc_wf] true
[remove_nb_down] true
[remove_nb_up] true
[remove_nb_minus] true
[remove_nb_plus] true
[remove_nb_stem] true
[isOverlapDistanceSatisfied_False] true
[isOverlapDistanceSatisfied_True] true
[get_applicableCuts_True] true
[get_applicableCuts_False] true
[get_all_section] true
[get_all_linears] true
[get_all_points] true
[get_all_signals] true
[get_reachableNetwork] true
[get_disconnectNetwork_sc1] true
[get_disconnectNetwork_with_points] true
[decomposed_sc1]
,→ ({"t2","t3","b1"},{"t2","b12","t11","t10","t7","t8","t6","t5","t3","t4","t9"})
[decomposed_sc1_wf] true
[decomposed_cc1]
,→ ({"b1","t2","t3","t6","t5","t8","t7","t4"},{"t7","b12","t11","t10","t5","t6","t8","t9"})
[decomposed_cc1_wf] true
[decompose_mc1] {{"t2","t3","b1"},{"t2","t8","t7","t6","t5","t3","t4"},
{"t11","b12","t10"},{"t7","t8","t5","t6","t11","t10","t9"}}
[decomposed_mc1_wf] true
[bcc] true
[sc1_M] true
[sc1] true
[sc2] true
[sc3] true
[sc4] true
D.3 C++ Results 93
/*======================================================
* File: $Name: Decomposition_DESIGN.rsl $
* Created: $Date: 2017-03-26 16:12:06 $
* Author: $Author: Cebrail Erdogan<[email protected]>$
* Description: Decomposition of Railway Networklayouts
*=======================================================
*/
Decomposition_COMMON
scheme Decomposition_DESIGN =
with T in
class
object C: Decomposition_COMMON
value
/*
* Single-cut decomposition.
* Decompose a network into two sub-networks, given a single cut
,→ specification.
*/
decompose: C.ITG.I.L.NetworkLayout >< C.SingleCut -~->
C.ITG.I.L.NetworkLayout >< C.ITG.I.L.NetworkLayout
decompose(n,sc) is
let
l_down = C.section_down(sc),
l_up = C.section_up(sc),
n_down = C.get_reachableNetwork(cut_applied_down,l_down),
n_up = C.get_reachableNetwork(cut_applied_up,l_up)
in
(n_down,n_up)
end
pre C.ITG.I.L.is_wf(n) /\ C.cut_wf(n,sc),
/*
* Cluster-cut decomposition.
* Decompose a network into two sub-networks, given a cluster-cut
,→ specification.
*/
decompose: C.ITG.I.L.NetworkLayout >< C.ClusterCut -~->
C.ITG.I.L.NetworkLayout >< C.ITG.I.L.NetworkLayout
96 E RSL Specifications
decompose(n,cc) is
let
l_ups = { C.section_up(c) | c:C.SingleCut :- c isin cc },
l_downs = { C.section_down(c) | c:C.SingleCut :- c isin cc },
/*
* Multi-Cut decomposition.
* Decompose a network into multiple networks, given a set of cuts.
* The input can be a mix of single- and cluster cuts.
*/
decompose: C.ITG.I.L.NetworkLayout >< C.MultiCut >< Bool -~->
C.ITG.I.L.NetworkLayout-set
decompose(n,mc, isOriginalNetwork) is
let
applicableCuts = C.get_applicableCuts(n,mc)
in
if applicableCuts = {}
then {n}
else let cut= hd applicableCuts in
let
(n1,n2) = case cut of
C.Cut_from_SingleCut(sc) -> decompose(n,sc),
C.Cut_from_ClusterCut(cc) -> decompose(n,cc)
end,
ns1 = decompose(n1, mc \ {cut}, false),
ns2 = decompose(n2, mc \ {cut}, false)
in
ns1 union ns2
end
end
end
end
pre C.ITG.I.L.is_wf(n) /\ if isOriginalNetwork then C.cuts_wf(n, mc) else
,→ true end
end
E.2 Decomposition_COMMON 97
E.2 Decomposition_COMMON
/*======================================================
* File: $ Name: Decomposition_COMMON.rsl $
* Created: $ Date: 2017-05-12 11:12:06 $
* Author: $ Author: Cebrail Erdogan<[email protected]> $
* Description: Common types and functions
*=======================================================
*/
InterlockingTableGenerator
scheme Decomposition_COMMON =
with T in
class
object ITG : InterlockingTableGenerator
type
BorderCut ::
section_down:SecId
section_up:SecId,
SingleCut = BorderCut,
ClusterCut = SingleCut-set,
MultiCut = Cut-set,
Cut == Cut_from_SingleCut(cut_to_singlecut: SingleCut) |
Cut_from_ClusterCut(cut_to_clustercut: ClusterCut)
value
/* Constant values */
MIN_SAFETY_DISTANCE : Distance = 50,
empty_n : ITG.I.L.NetworkLayout =
ITG.I.L.mk_NetworkLayout([], [], []),
empty_mc : MultiCut = {}
~ITG.I.L.is_boundary(l_up,n) /\
/* Do we have a down- and up signal from linears in cut
,→ specification? */
DOWN isin dom ITG.I.L.signals(l_up,n) /\ UP isin dom
,→ ITG.I.L.signals(l_down,n)) /\
/* Check if linears are is still reachable when
,→ disconnected -- Disconnects all cuts every time */
let disconnected_network = get_disconnectedNetwork(n,cc)
,→ in
l_up ~isin
,→ get_reachableNetworkSet(disconnected_network,l_down)
,→ /\
l_down ~isin
,→ get_reachableNetworkSet(disconnected_network,l_up)
end
end
),
/*
* SC1_M
* Obj.: Check for overlaps requirements, is the minimum distance satisfied?
* Type: (Manual Check) - Pre condition
*/
SC1_M: ITG.I.L.NetworkLayout >< SingleCut -> Bool
SC1_M(n,sc) is
let l_up_id = section_up(sc),
l_down_id = section_down(sc),
l_up = ITG.I.L.get_linear(l_up_id,n),
l_down = ITG.I.L.get_linear(l_down_id,n),
mb_up = ITG.I.L.get_markerboard(ITG.I.L.usig(l_down_id,n), n),
mb_down = ITG.I.L.get_markerboard(ITG.I.L.dsig(l_up_id,n), n)
in
(isOverlapDistanceSatisfied(mb_down,l_down) /\
isOverlapDistanceSatisfied(mb_up, l_up))
end,
/* SC1:
* Objective: Found overlap sections must not reside in the other generated
,→ table.
*/
SC1: ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout
,→ -> Bool
SC1(n,n_down,n_up) is
let
t = ITG.mk_table(n),
down_routes = get_sub_routes(n_down,t),
up_routes = get_sub_routes(n_up,t)
in
(all r : ITG.I.Route :- r isin rng down_routes =>
(all s: SecId :- s isin ITG.I.overlap(r) =>
s isin ITG.I.L.sections(n_down)))
/\
(all r : ITG.I.Route :- r isin rng up_routes =>
(all s: SecId :- s isin ITG.I.overlap(r) =>
s isin ITG.I.L.sections(n_up)))
end,
100 E RSL Specifications
/* SC2:
* Objective: Found point requirements must not reference points that reside
,→ in the other generated table.
*/
SC2: ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout
,→ -> Bool
SC2(n, n_down,n_up) is
let
t = ITG.mk_table(n),
down_routes = get_sub_routes(n_down,t),
up_routes = get_sub_routes(n_up,t)
in
(all r : ITG.I.Route :- r isin rng down_routes =>
(all s_id : SecId :- s_id isin dom ITG.I.points(r) =>
s_id isin ITG.I.L.sections(n_down)))
/\
(all r : ITG.I.Route :- r isin rng up_routes =>
(all s_id : SecId :- s_id isin dom ITG.I.points(r) =>
s_id isin ITG.I.L.sections(n_up)))
end,
/* SC3:
* Objective: Found marker boards must not reside in the other generated
,→ table.
*/
SC3: ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout
,→ -> Bool
SC3(n, n_down,n_up) is
let
t = ITG.mk_table(n),
down_routes = get_sub_routes(n_down,t),
up_routes = get_sub_routes(n_up,t)
in
(all r : ITG.I.Route :- r isin rng down_routes =>
(all m_id : MbId :- m_id isin ITG.I.signals(r) =>
m_id isin dom ITG.I.L.marker_boards(n_down)))
/\
(all r : ITG.I.Route :- r isin rng up_routes =>
(all m_id : MbId :- m_id isin ITG.I.signals(r) =>
m_id isin dom ITG.I.L.marker_boards(n_up)))
end,
/* SC4:
* Objective: Found conflicting routes must not reside in the other generated
,→ table.
*/
SC4: ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout
,→ -> Bool
SC4(n, n_down,n_up) is
let
t = ITG.mk_table(n),
down_routes = get_sub_routes(n_down,t),
up_routes = get_sub_routes(n_up,t)
in
(all r : ITG.I.Route :- r isin rng down_routes =>
(all r_id : RouteId :- r_id isin ITG.I.conflicts(r) =>
r_id isin dom down_routes))
/\
E.2 Decomposition_COMMON 101
linearsToDisconnect =
-- if down section is a linear
[ l +> remove_nb(ITG.I.L.get_linear(l,n), UP) | l:SecId :- l
,→ isin ITG.I.L.linears(n) /\ l = secIdDown] !!
-- if up section is a linear
[ l +> remove_nb(ITG.I.L.get_linear(l,n), DOWN) | l:SecId :- l
,→ isin ITG.I.L.linears(n) /\ l = secIdUp],
pointsToDisconnect =
-- if down section is a point
-- point end to disconnect: ITG.I.L.get_p_end_by_nb_id(s,s,n)
[ p +> remove_nb(ITG.I.L.get_point(secIdDown,n),
,→ ITG.I.L.get_p_end_by_nb_id(secIdDown, secIdUp, n)) |
,→ p:SecId :- p isin ITG.I.L.points(n) /\ p = secIdDown] !!
-- if up section is a linear
[ p +> remove_nb(ITG.I.L.get_point(secIdUp,n),
,→ ITG.I.L.get_p_end_by_nb_id(secIdUp, secIdDown, n)) |
,→ p:SecId :- p isin ITG.I.L.points(n) /\ p = secIdUp]
in
-- Update the network by adding the new boundaries
ITG.I.L.mk_NetworkLayout(linears !! linearsToDisconnect, points !!
,→ pointsToDisconnect, ITG.I.L.marker_boards(n))
end
pre ITG.I.L.are_neighbors(secIdDown, secIdUp, n),
ITG.I.L.mk_NetworkLayout(ITG.I.L.linears(n), ITG.I.L.points(n),
,→ ITG.I.L.marker_boards(n) \ extra_mbs)
end,
/*
* Get all sections by discovering through neighbors.
* Recoursively accumalate all the sections in both directions.
*/
get_all_sections: ITG.I.L.NetworkLayout >< SecId-set >< SecId-set -~->
,→ SecId-set
get_all_sections(n,tv,v) is
if tv = {} then v -- If no
,→ unvisited sections left, then finish
else
let
current = hd tv, --
,→ Select an element from to visit set
visited = {current} union v, -- Add
,→ current section to visited
toVisit = (tv union ITG.I.L.get_neighbors(current,n)) \ visited --
,→ Update toVisit and prevent endless loop
in
get_all_sections(n,toVisit,visited) -- Call
,→ function with updated args
end
end,
get_reachableNetwork(n,s) is
let
-- Get all sections
sections = get_all_sections(n,{s},{}),
-- Get all linears from given sections
linears = get_all_linears(n,sections),
-- Get all points from given sections
points = get_all_points(n, sections),
-- Get all signals from given sections (signals only exists in linears)
signals = get_all_signals(n, sections)
in
-- Instantiate a new network layout
ITG.I.L.mk_NetworkLayout(linears,points,signals)
end
pre ITG.I.L.s_exists(s,n),
/* Auxiliary functions */
value
remove_nb: ITG.I.L.Linear >< LinearEnd -> ITG.I.L.Linear
remove_nb(l,le) is
ITG.I.L.mk_Linear(ITG.I.L.neighbors(l) \ {le}, ITG.I.L.length(l)),
/*
* Simpler representations of sections and signals
* For two sub-networks
*/
decomposed_sec_repr: ITG.I.L.NetworkLayout >< ITG.I.L.NetworkLayout ->
,→ SecId-set >< SecId-set
decomposed_sec_repr(n1,n2) is
(ITG.I.L.sections(n1), ITG.I.L.sections(n2)),
/*
* For multi cut
*/
decomposed_sec_repr: ITG.I.L.NetworkLayout-set >< (SecId-set)-set ->
,→ (SecId-set)-set
decomposed_sec_repr(n, secs) is
if n = {} then secs
else
E.2 Decomposition_COMMON 105
let h = hd n in
decomposed_sec_repr(n \ {h}, secs union {ITG.I.L.sections(h)})
end
end,
end
106
APPENDIX F
C++ Code
This appendix contains the C++ files of the most importants parts of the decomposition
tool. The cut types and the main decomposition methods are part of the shown listings.
F.1.1 Cut.h
#ifndef CUT_H
#define CUT_H
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <set>
#include <list>
#include "RttTgenDkIxlComponent.h"
struct CutTypes {
typedef enum{
UNDEF = 0,
BORDERCUT = 1,
CLUSTERCUT = 2,
MULTICUT = 3
} cut_type_t;
};
public:
Cut(std::string n, std::string oid = "<undefined id>" , CutTypes::cut_type_t t
,→ = CutTypes::UNDEF)
: RttTgenDkIxlComponent(n, oid), type(t) {}
};
#endif
F.1.2 SingleCut.h
#ifndef SINGLECUT_H
#define SINGLECUT_H
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <set>
#include <list>
#include "RttTgenDkIxlLinear.h"
#include "Cut.h"
#endif
F.1.3 BorderCut.h
#ifndef BORDERCUT_H
#define BORDERCUT_H
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <set>
#include <list>
#include "RttTgenDkIxlLinear.h"
#include "SingleCut.h"
public:
BorderCut(std::string oid)
: SingleCut("BorderCut", oid, CutTypes::BORDERCUT) {}
F.1 Cut Types 109
#endif
F.1.4 ClusterCut.h
#ifndef CLUSTERCUT_H
#define CLUSTERCUT_H
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include "Cut.h"
#include "BorderCut.h"
public:
ClusterCut(std::string oid)
: Cut("CluterCut", oid, CutTypes::CLUSTERCUT) {}
#endif
F.1.5 MultiCut.h
#ifndef MULTICUT_H
#define MULTICUT_H
#include <iostream>
#include <sstream>
#include <list>
#include "Cut.h"
#include "BorderCut.h"
#include "ClusterCut.h"
110 F C++ Code
public:
MultiCut(std::string oid)
: Cut("MultiCut", oid, CutTypes::MULTICUT) {}
#endif
F.2.1 main.cpp
#include "Decomposition.h"
#include "parser/DecompositionParser.h"
#include "xmlWriter/DecompositionXmlWriter.h"
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
string out_path;
// write up network
interlocking -> setNetworkLayout(upDownNetworks.up);
xmlWriter -> xmlWriteMainDoc(out_path + interlocking -> getOid() +
,→ "_up.xml", interlocking);
break;
case CutTypes::CLUSTERCUT:
cout << "ClusterCut Detected" << endl;
upDownNetworks = decomposition -> decompose(network, (ClusterCut*) cut);
// write up network
interlocking -> setNetworkLayout(upDownNetworks.up);
xmlWriter -> xmlWriteMainDoc(out_path + interlocking -> getOid() +
,→ "_up.xml", interlocking);
break;
case CutTypes::MULTICUT:
cout << "MultiCut Detected" << endl;
networks = decomposition -> decompose(network, (MultiCut*) cut);
int cnt = 0;
for(const auto& n : networks){
interlocking -> setNetworkLayout(n);
xmlWriter -> xmlWriteMainDoc(out_path + interlocking -> getOid() + "_"
,→ + std::to_string(++cnt) + ".xml", interlocking);
}
break;
}
return 0;
}
F.2 Main decomposition files 113
F.2.2 Decomposition.cpp
#include "Decomposition.h"
#include <stdio.h>
#include <string.h>
Decomposition::Decomposition(){
common = new DecompositionCommon();
}
upDownNetworks_t networks;
bool isDownSubnetCreated = common -> createSubnet(downNetwork, sc,
,→ direction_t::DOWN);
bool isUpSubnetCreated = common -> createSubnet(upNetwork, sc, direction_t::UP);
if (isDownSubnetCreated && isUpSubnetCreated){
networks.down = common -> reachableNetwork(downNetwork, l_down);
networks.up = common -> reachableNetwork(upNetwork, l_up);
}
return networks;
}
upDownNetworks_t networks;
if (isDownSubnetCreated && isUpSubnetCreated){
networks.down = common -> reachableNetwork(downNetwork, l_down);
networks.up = common -> reachableNetwork(upNetwork, l_up);
}
networks.down = downNetwork;
networks.up = upNetwork;
return networks;
}
114 F C++ Code
if (applicableCutOids.size() == 0){
networks_t n = {network};
return n;
}
else{
string cutOid = applicableCutOids.front();
applicableCutOids.pop_front();
CutTypes::cut_type_t cutType = mc -> getCut(cutOid) -> getCutType();
upDownNetworks_t ns;
if (cutType == CutTypes::BORDERCUT){
ns = decompose(network, mc -> getBorderCut(cutOid));
list<BorderCut*> borderCuts = mc -> getBorderCuts();
borderCuts.remove(mc -> getBorderCut(cutOid));
mc -> setBorderCuts(borderCuts);
}
else if (cutType == CutTypes::CLUSTERCUT){
ns = decompose(network, mc -> getClusterCut(cutOid));
list<ClusterCut*> clusterCuts = mc -> getClusterCuts();
clusterCuts.remove(mc -> getClusterCut(cutOid));
mc -> setClusterCuts(clusterCuts);
}
else{
//Throw error
}
return mergedNetworks;
}
}
Bibliography
[1] A selection of projects which have used RAISE. url: http://spd-web.terma.
com / Projects / RAISE / project . html (visited on July 14, 2017) (cited on
page 8).
[2] About the project - Robustrails. url: http://www.robustrails.man.dtu.dk/
About-the-project (visited on July 13, 2017) (cited on page 3).
[3] Depth First Search and Breadth First Search in Python. url: http://eddmann.
com/posts/depth-first-search-and-breadth-first-search-in-python/
(visited on July 21, 2017) (cited on page 40).
[4] Alessandro Fantechi, Anne E. Haxthausen, and Hugo Daniel Macedo. “Compo-
sitional Verification of Interlocking Systems for Large Stations”. In: Proceedings
of SEFM’ 2017. Edited by Alessandro Cimatti and Marjan Sirjani. Volume 1046.
Lecture Notes in Computer Science. Springer International Publishing, 2017
(cited on page 18).
[5] Andreas Foldager. “A Graphical Domain-specific Language for Railway Interlock-
ing Systems , Et Grafisk Domænespecifikt Sprog for Jernbane-sikringsanlæg”.
und. 2015 (cited on pages 7, 68).
[6] Anne E. Haxthausen and Peter H. Østergaard. “On the Use of Static Checking in
the Verification of Interlocking Systems”. In: Leveraging Applications of Formal
Methods, Verification and Validation: Discussion, Dissemination, Applications:
7th International Symposium, ISoLA 2016, Imperial, Corfu, Greece, October
10-14, 2016, Proceedings, Part II. Edited by Tiziana Margaria and Bernhard
Steffen. Cham: Springer International Publishing, 2016, pages 266–278. isbn:
978-3-319-47169-3. doi: 10.1007/978-3-319-47169-3_19. url: http://dx.
doi.org/10.1007/978-3-319-47169-3_19 (cited on pages 1, 6).
[7] Hugo D. Macedo, Alessandro Fantechi, and Anne E. Haxthausen. “Compositional
Verification of Multi-Station Interlocking Systems”. In: Leveraging Applications
of Formal Methods, Verification and Validation: Discussion, Dissemination,
Applications, Part II. Volume 9953. Lecture Notes in Computer Science. Springer
International Publishing AG, 2016, pages 279–293 (cited on pages 4, 10, 63, 64).
[8] Hugo Daniel Macedo, Alessandro Fantechi, and Anne E. Haxthausen. “Composi-
tional Model Checking of Interlocking Systems for Lines with Multiple Stations”.
In: NASA Formal Methods: 9th International Symposium, NFM 2017, Proceed-
ings. Edited by Clark Barrett, Misty Davies, and Temesghen Kahsai. Springer
International Publishing, 2017, pages 146–162. isbn: 978-3-319-57288-8. doi:
116 Bibliography