diff --git a/docs/source/_static/sbahn_berlin.html b/docs/source/_static/metro_berlin.html
similarity index 96%
rename from docs/source/_static/sbahn_berlin.html
rename to docs/source/_static/metro_berlin.html
index 9fed08ab..36c40e1d 100644
--- a/docs/source/_static/sbahn_berlin.html
+++ b/docs/source/_static/metro_berlin.html
@@ -1,14 +1,109 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/docs/source/mods/figures/berlin_metro_oct.png b/docs/source/mods/figures/berlin_metro_oct.png
new file mode 100644
index 00000000..bb95b251
Binary files /dev/null and b/docs/source/mods/figures/berlin_metro_oct.png differ
diff --git a/docs/source/mods/figures/berlin_metro_orig.png b/docs/source/mods/figures/berlin_metro_orig.png
new file mode 100644
index 00000000..b3476618
Binary files /dev/null and b/docs/source/mods/figures/berlin_metro_orig.png differ
diff --git a/docs/source/mods/figures/berlin_metro_reduced_oct.png b/docs/source/mods/figures/berlin_metro_reduced_oct.png
new file mode 100644
index 00000000..6c1ab721
Binary files /dev/null and b/docs/source/mods/figures/berlin_metro_reduced_oct.png differ
diff --git a/docs/source/mods/figures/berlin_metro_reduced_orig.png b/docs/source/mods/figures/berlin_metro_reduced_orig.png
new file mode 100644
index 00000000..5a605c01
Binary files /dev/null and b/docs/source/mods/figures/berlin_metro_reduced_orig.png differ
diff --git a/docs/source/mods/figures/sberlin_oct.png b/docs/source/mods/figures/sberlin_oct.png
deleted file mode 100644
index 49c0a7a1..00000000
Binary files a/docs/source/mods/figures/sberlin_oct.png and /dev/null differ
diff --git a/docs/source/mods/figures/sberlin_orig.png b/docs/source/mods/figures/sberlin_orig.png
deleted file mode 100644
index 61278897..00000000
Binary files a/docs/source/mods/figures/sberlin_orig.png and /dev/null differ
diff --git a/docs/source/mods/metromap.rst b/docs/source/mods/metromap.rst
index 3e6504ff..3f293652 100644
--- a/docs/source/mods/metromap.rst
+++ b/docs/source/mods/metromap.rst
@@ -332,7 +332,7 @@ is too bulky), the different aspects of the model are discussed below.
most one of its adjacent edges.
All these improving constraints are added by default. However, a parameter
- ``improve_lp`` that can be set to False and then these improving
+ ``improve_lp`` is provided that can be set to False and then these improving
constraints are not added.
Code and Inputs
@@ -352,20 +352,21 @@ An example of the inputs with the respective requirements is shown below.
>>> import networkx as nx
>>> from gurobi_optimods import datasets
- >>> graph, linepath_data = datasets.load_sberlin_graph_data()
+ >>> graph, linepath_data = datasets.load_metro_berlin_reduced_graph_data()
>>> print(graph)
- Graph with 167 nodes and 175 edges
+ Graph with 29 nodes and 32 edges
>>> pos_orig = nx.get_node_attributes(graph, 'pos')
>>> len(pos_orig)
- 167
+ 29
>>> linepath_data.head(4)
linename edge_source edge_target
- 0 S1 100 78
- 1 S1 78 23
- 2 S1 23 20
- 3 S1 20 60
+ 0 U1 147 50
+ 1 U1 50 82
+ 2 U1 82 127
+ 3 U1 127 53
-For the example, we used data from the S-Bahn Berlin network. The graph includes
+For the example, we used data from the Berlin metro network. For demonstration,
+we use only a small part of the whole network. The graph includes
the node attribute ``pos`` that contains a tuple of x- and y-coordinates for
the original position. The linepath_data must be consistent with
the graph. For example, ``edge_source``, ``edge_target`` in the
@@ -390,9 +391,13 @@ The OptiMod can be run as follows:
>>> from gurobi_optimods import datasets
>>> from gurobi_optimods.metromap import metromap
- >>> graph, linepath_data = datasets.load_sberlin_graph_data()
+ >>> graph, linepath_data = datasets.load_metro_berlin_reduced_graph_data()
>>> graph_out, edge_directions = metromap(
- ... graph, linepath_data, include_planarity=False, verbose=False, time_limit=2
+ ... graph,
+ ... linepath_data,
+ ... include_planarity=False,
+ ... improve_lp=False,
+ ... verbose=False
... )
>>> # Show that input and output graphs are isomorphic (structural equivalent)
>>> import networkx as nx
@@ -401,17 +406,18 @@ The OptiMod can be run as follows:
>>> # Show the first 4 nodes with their attributes
>>> first_four_nodes_with_attrs = list(graph_out.nodes.data())[:4]
>>> print(first_four_nodes_with_attrs)
- [(100, {'pos': (13.248432, 52.754362), 'pos_oct': (7.0, 33.0)}),
- (78, {'pos': (13.263191, 52.741273), 'pos_oct': (8.0, 32.0)}),
- (23, {'pos': (13.276771, 52.714491), 'pos_oct': (9.0, 31.0)}),
- (20, {'pos': (13.288417, 52.687871), 'pos_oct': (10.0, 30.0)})]
+ [(50, {'pos': [13.428468, 52.499035], 'pos_oct': (5.0, 25.0)}),
+ (82, {'pos': [13.417748, 52.499047], 'pos_oct': (4.0, 25.0)}),
+ (127, {'pos': [13.406531, 52.498274], 'pos_oct': (2.0, 25.0)}),
+ (53, {'pos': [13.39176, 52.497774], 'pos_oct': (1.0, 25.0)})]
Note, for this demonstration the parameter ``include_planarity`` is set to
-False, and we chose a time limit of 2 seconds. This is done to see results
-faster. For this example, the planarity constraints are usually satisfied. If
-the planarity constraints should be included in the computation, the parameter
-``include_planarity`` can be omitted or set to True.
-The ``time_limit`` parameter can also be omitted if no time limit shall be set.
+False, and we skip the improving constraints. This is done so that the test
+works with the Gurobi test license. For this example, the planarity constraints
+are usually satisfied. If the planarity constraints should be included in the
+computation, the parameter ``include_planarity`` can be omitted or set to True.
+If a full Gurobi license is available, test full Berlin metro network can be
+loaded and tested with ``datasets.load_metro_berlin_graph_data()``.
The graph can be plotted using the networkx plotting function, for example, as
follows::
@@ -439,14 +445,24 @@ As a comparison the original node positions can be plotted as well::
)
Below is a ``networkx`` plot of the graph with the original positions (left) and
-the computed octilinear positions (right) for the S-Bahn Berlin network.
+the computed octilinear positions (right) for the Berlin metro network. First
+the small part is shown and below the full network.
-.. image:: figures/sberlin_orig.png
+.. image:: figures/berlin_metro_reduced_orig.png
:width: 49%
-.. image:: figures/sberlin_oct.png
+.. image:: figures/berlin_metro_reduced_oct.png
:width: 49%
+.. image:: figures/berlin_metro_orig.png
+ :width: 49%
+.. image:: figures/berlin_metro_oct.png
+ :width: 49%
+
+Note that optimizing a subnetwork only includes fewer restrictions and hence
+most probably results in a different outcome than when considered within the
+complete network.
+
We provide a method to plot the lines in the octilinear representation using ``plotly``.
In order to use this functionality, the ``plotly`` package is needed.
@@ -459,11 +475,11 @@ The plot function can be called as follows::
The following figure is an example of the above call, it shows the lines in the
octilinear representation of the S-Bahn Berlin network.
-(Use `link <../_static/sbahn_berlin.html>`_ to open in full screen.)
+(Use `link <../_static/metro_berlin.html>`_ to open in full screen.)
.. raw:: html
-
+
Note that plotting the lines in the octilinear network is an art or a further
@@ -539,7 +555,8 @@ this OptiMod. Here is an example of how this could be done
for number, row in node_data.set_index("number").iterrows():
graph.add_node(number, pos=(row["posx"], row["posy"]))
# compute and plot metromap
- graph_out, edge_directions = metromap(graph, linepath_data_sol, verbose=False)
+ graph_out, edge_directions = metromap(
+ graph, linepath_data_sol, penalty_line_bends=False,verbose=False)
plot_map(graph_out, edge_directions, linepath_data_sol)
diff --git a/src/gurobi_optimods/data/graphs/sberlin_edges.csv b/src/gurobi_optimods/data/graphs/sberlin_edges.csv
deleted file mode 100644
index e56aba20..00000000
--- a/src/gurobi_optimods/data/graphs/sberlin_edges.csv
+++ /dev/null
@@ -1,211 +0,0 @@
-source,target
-100,78
-78,23
-23,20
-20,60
-60,42
-42,58
-58,147
-147,158
-158,157
-157,129
-129,159
-159,24
-24,44
-44,64
-64,96
-96,101
-101,41
-41,26
-26,112
-112,6
-6,162
-162,67
-67,125
-125,38
-38,34
-34,118
-118,25
-25,83
-83,139
-139,164
-164,91
-91,123
-123,95
-95,148
-13,14
-14,165
-165,120
-120,27
-27,71
-71,21
-21,106
-106,105
-105,24
-6,163
-163,141
-141,114
-114,7
-7,86
-86,28
-28,122
-122,80
-80,84
-84,22
-56,55
-55,124
-124,142
-142,31
-31,69
-69,4
-4,129
-114,140
-140,77
-77,81
-81,102
-102,82
-82,143
-33,156
-156,115
-115,40
-40,59
-59,75
-75,161
-161,70
-70,15
-15,119
-119,104
-104,149
-149,103
-103,66
-66,3
-3,50
-50,41
-41,12
-12,10
-10,145
-145,167
-167,121
-121,30
-30,154
-154,90
-90,52
-52,99
-99,108
-108,138
-138,131
-104,146
-146,130
-130,94
-94,57
-57,144
-144,141
-141,125
-125,65
-65,29
-29,54
-54,62
-62,51
-51,154
-154,89
-89,152
-152,68
-68,17
-17,153
-153,151
-151,44
-44,128
-128,113
-113,45
-45,76
-76,134
-134,36
-36,104
-104,36
-36,134
-134,76
-76,45
-45,113
-113,128
-128,44
-44,151
-151,153
-153,17
-17,68
-68,152
-152,89
-89,154
-154,51
-51,62
-62,54
-54,29
-29,65
-65,125
-125,141
-141,144
-144,57
-57,94
-94,130
-130,146
-146,104
-94,73
-73,9
-9,126
-126,16
-16,1
-1,5
-5,49
-49,35
-1,48
-48,32
-32,166
-166,155
-155,74
-126,98
-98,132
-136,137
-137,53
-53,135
-135,107
-107,37
-37,93
-93,63
-63,19
-19,85
-85,72
-72,160
-160,18
-18,39
-39,79
-79,97
-97,104
-2,88
-88,116
-116,87
-87,110
-110,133
-133,39
-154,47
-47,95
-148,46
-46,8
-8,111
-150,61
-61,43
-43,133
-60,11
-11,127
-127,92
-92,21
-24,128
-146,109
-109,9
-35,49
-49,5
-5,1
-1,16
-16,126
-126,9
-9,109
-109,146
-146,149
diff --git a/src/gurobi_optimods/data/graphs/sberlin_linepaths_sol.csv b/src/gurobi_optimods/data/graphs/sberlin_linepaths_sol.csv
deleted file mode 100644
index 233eaf98..00000000
--- a/src/gurobi_optimods/data/graphs/sberlin_linepaths_sol.csv
+++ /dev/null
@@ -1,340 +0,0 @@
-linename,edge_source,edge_target
-S1,100,78
-S1,78,23
-S1,23,20
-S1,20,60
-S1,60,42
-S1,42,58
-S1,58,147
-S1,147,158
-S1,158,157
-S1,157,129
-S1,129,159
-S1,159,24
-S1,24,44
-S1,44,64
-S1,64,96
-S1,96,101
-S1,101,41
-S1,41,26
-S1,26,112
-S1,112,6
-S1,6,162
-S1,162,67
-S1,67,125
-S1,125,38
-S1,38,34
-S1,34,118
-S1,118,25
-S1,25,83
-S1,83,139
-S1,139,164
-S1,164,91
-S1,91,123
-S1,123,95
-S1,95,148
-S2,13,14
-S2,14,165
-S2,165,120
-S2,120,27
-S2,27,71
-S2,71,21
-S2,21,106
-S2,106,105
-S2,105,24
-S2,24,44
-S2,44,64
-S2,64,96
-S2,96,101
-S2,101,41
-S2,41,26
-S2,26,112
-S2,112,6
-S2,6,163
-S2,163,141
-S2,141,114
-S2,114,7
-S2,7,86
-S2,86,28
-S2,28,122
-S2,122,80
-S2,80,84
-S2,84,22
-S25,56,55
-S25,55,124
-S25,124,142
-S25,142,31
-S25,31,69
-S25,69,4
-S25,4,129
-S25,129,159
-S25,159,24
-S25,24,44
-S25,44,64
-S25,64,96
-S25,96,101
-S25,101,41
-S25,41,26
-S25,26,112
-S25,112,6
-S25,6,163
-S25,163,141
-S25,141,114
-S25,114,140
-S25,140,77
-S25,77,81
-S25,81,102
-S25,102,82
-S25,82,143
-S3,33,156
-S3,156,115
-S3,115,40
-S3,40,59
-S3,59,75
-S3,75,161
-S3,161,70
-S3,70,15
-S3,15,119
-S3,119,104
-S3,104,149
-S3,149,103
-S3,103,66
-S3,66,3
-S3,3,50
-S3,50,41
-S3,41,12
-S3,12,10
-S3,10,145
-S3,145,167
-S3,167,121
-S3,121,30
-S3,30,154
-S3,154,90
-S3,90,52
-S3,52,99
-S3,99,108
-S3,108,138
-S3,138,131
-S41,104,146
-S41,146,130
-S41,130,94
-S41,94,57
-S41,57,144
-S41,144,141
-S41,141,125
-S41,125,65
-S41,65,29
-S41,29,54
-S41,54,62
-S41,62,51
-S41,51,154
-S41,154,89
-S41,89,152
-S41,152,68
-S41,68,17
-S41,17,153
-S41,153,151
-S41,151,44
-S41,44,128
-S41,128,113
-S41,113,45
-S41,45,76
-S41,76,134
-S41,134,36
-S41,36,104
-S42,104,36
-S42,36,134
-S42,134,76
-S42,76,45
-S42,45,113
-S42,113,128
-S42,128,44
-S42,44,151
-S42,151,153
-S42,153,17
-S42,17,68
-S42,68,152
-S42,152,89
-S42,89,154
-S42,154,51
-S42,51,62
-S42,62,54
-S42,54,29
-S42,29,65
-S42,65,125
-S42,125,141
-S42,141,144
-S42,144,57
-S42,57,94
-S42,94,130
-S42,130,146
-S42,146,104
-S45,141,144
-S45,144,57
-S45,57,94
-S45,94,73
-S45,73,9
-S45,9,126
-S45,126,16
-S45,16,1
-S45,1,5
-S45,5,49
-S45,49,35
-S46,152,89
-S46,89,154
-S46,154,51
-S46,51,62
-S46,62,54
-S46,54,29
-S46,29,65
-S46,65,125
-S46,125,141
-S46,141,144
-S46,144,57
-S46,57,94
-S46,94,73
-S46,73,9
-S46,9,126
-S46,126,16
-S46,16,1
-S46,1,48
-S46,48,32
-S46,32,166
-S46,166,155
-S46,155,74
-S47,57,94
-S47,94,73
-S47,73,9
-S47,9,126
-S47,126,98
-S47,98,132
-S5,136,137
-S5,137,53
-S5,53,135
-S5,135,107
-S5,107,37
-S5,37,93
-S5,93,63
-S5,63,19
-S5,19,85
-S5,85,72
-S5,72,160
-S5,160,18
-S5,18,39
-S5,39,79
-S5,79,97
-S5,97,104
-S5,104,149
-S5,149,103
-S5,103,66
-S5,66,3
-S5,3,50
-S5,50,41
-S5,41,12
-S5,12,10
-S5,10,145
-S5,145,167
-S5,167,121
-S5,121,30
-S5,30,154
-S7,2,88
-S7,88,116
-S7,116,87
-S7,87,110
-S7,110,133
-S7,133,39
-S7,39,79
-S7,79,97
-S7,97,104
-S7,104,149
-S7,149,103
-S7,103,66
-S7,66,3
-S7,3,50
-S7,50,41
-S7,41,12
-S7,12,10
-S7,10,145
-S7,145,167
-S7,167,121
-S7,121,30
-S7,30,154
-S7,154,47
-S7,47,95
-S7,95,148
-S7,148,46
-S7,46,8
-S7,8,111
-S75,150,61
-S75,61,43
-S75,43,133
-S75,133,39
-S75,39,79
-S75,79,97
-S75,97,104
-S8,20,60
-S8,60,11
-S8,11,127
-S8,127,92
-S8,92,21
-S8,21,106
-S8,106,105
-S8,105,24
-S8,24,128
-S8,128,113
-S8,113,45
-S8,45,76
-S8,76,134
-S8,134,36
-S8,36,104
-S8,104,146
-S8,146,109
-S8,109,9
-S8,9,126
-S8,126,16
-S8,16,1
-S8,1,48
-S8,48,32
-S8,32,166
-S85,105,24
-S85,24,128
-S85,128,113
-S85,113,45
-S85,45,76
-S85,76,134
-S85,134,36
-S85,36,104
-S85,104,146
-S85,146,109
-S85,109,9
-S85,9,126
-S85,126,16
-S85,16,1
-S85,1,48
-S9,35,49
-S9,49,5
-S9,5,1
-S9,1,16
-S9,16,126
-S9,126,9
-S9,9,109
-S9,109,146
-S9,146,149
-S9,149,103
-S9,103,66
-S9,66,3
-S9,3,50
-S9,50,41
-S9,41,12
-S9,12,10
-S9,10,145
-S9,145,167
-S9,167,121
-S9,121,30
-S9,30,154
-S9,154,90
-S9,90,52
-S9,52,99
-S9,99,108
-S9,108,138
-S9,138,131
diff --git a/src/gurobi_optimods/data/graphs/sberlin_nodes.csv b/src/gurobi_optimods/data/graphs/sberlin_nodes.csv
deleted file mode 100644
index f1b3b2e0..00000000
--- a/src/gurobi_optimods/data/graphs/sberlin_nodes.csv
+++ /dev/null
@@ -1,168 +0,0 @@
-number,name,posx,posy
-1,Adlershof,13.540553,52.435102
-2,Ahrensfelde,13.566118,52.571564
-3,Alexanderplatz,13.411267,52.521512
-4,Alt-Reinickendorf,13.349747,52.577969
-5,Altglienicke,13.559602,52.407791
-6,Anhalter Bahnhof,13.382077,52.504538
-7,Attilastr.,13.361177,52.447298
-8,Babelsberg,13.094623,52.391372
-9,Baumschulenweg,13.489505,52.467581
-10,Bellevue,13.347098,52.519951
-11,Bergfelde,13.321455,52.669695
-12,Berlin Hauptbahnhof,13.368924,52.525847
-13,Bernau,13.593034,52.676233
-14,Bernau-Friedenstal,13.564597,52.668369
-15,Betriebsbahnhof Rummelsburg,13.497509,52.493957
-16,Betriebsbahnhof Schoeneweide,13.524028,52.446695
-17,Beusselstr.,13.328703,52.534314
-18,Biesdorf,13.555035,52.513059
-19,Birkenstein,13.648591,52.515755
-20,Birkenwerder,13.288417,52.687871
-21,Blankenburg,13.442972,52.591069
-22,Blankenfelde,13.415908,52.337628
-23,Borgsdorf,13.276771,52.714491
-24,Bornholmer Str.,13.39784,52.554754
-25,Botanischer Garten,13.306041,52.447552
-26,Brandenburger Tor,13.381937,52.516511
-27,Buch,13.492452,52.636614
-28,Buckower Chaussee,13.382689,52.410919
-29,Bundesplatz,13.329149,52.477366
-30,Charlottenburg,13.305212,52.505052
-31,Eichborndamm,13.315583,52.577545
-32,Eichwalde,13.614966,52.372085
-33,Erkner,13.752249,52.428396
-34,Feuerbachstr.,13.332412,52.463578
-35,Flughafen Berlin-Schoenefeld,13.513522,52.390792
-36,Frankfurter Allee,13.4753,52.513613
-37,Fredersdorf,13.761324,52.526461
-38,Friedenau,13.340598,52.470002
-39,Friedrichsfelde Ost,13.520043,52.513747
-40,Friedrichshagen,13.625462,52.45709
-41,Friedrichstr.,13.387153,52.52027
-42,Frohnau,13.289564,52.632958
-43,Gehrenseestr.,13.525653,52.555736
-44,Gesundbrunnen,13.388372,52.548637
-45,Greifswalder Str.,13.438356,52.540724
-46,Griebnitzsee,13.128917,52.393988
-47,Grunewald,13.261944,52.48868
-48,Gruenau,13.574018,52.412714
-49,Gruenbergallee,13.543222,52.399539
-50,Hackescher Markt,13.402358,52.522607
-51,Halensee,13.290151,52.496698
-52,Heerstr.,13.258514,52.508273
-53,Hegermuehle,13.86679,52.549039
-54,Heidelberger Platz,13.311843,52.479446
-55,Heiligensee,13.228667,52.625148
-56,Hennigsdorf,13.205875,52.637866
-57,Hermannstr.,13.431704,52.467181
-58,Hermsdorf,13.306804,52.618165
-59,Hirschgarten,13.60148,52.457903
-60,Hohen Neuendorf,13.287224,52.669434
-61,Hohenschoenhausen,13.513698,52.566549
-62,Hohenzollerndamm,13.300712,52.488314
-63,Hoppegarten,13.673889,52.518141
-64,Humboldthain,13.378726,52.544742
-65,Innsbrucker Platz,13.342875,52.4781
-66,Jannowitzbruecke,13.418027,52.5155
-67,Julius-Leber-Bruecke,13.360775,52.486263
-68,Jungfernheide,13.299064,52.530275
-69,Karl-Bonhoeffer-Nervenklinik,13.332921,52.578169
-70,Karlshorst,13.525981,52.481038
-71,Karow,13.470081,52.615755
-72,Kaulsdorf,13.58903,52.512122
-73,Koellnische Heide,13.467529,52.469168
-74,Koenigs Wusterhausen,13.630568,52.296921
-75,Koepenick,13.579543,52.458692
-76,Landsberger Allee,13.455944,52.528772
-77,Lankwitz,13.34276,52.439034
-78,Lehnitz,13.263191,52.741273
-79,Lichtenberg,13.498228,52.510754
-80,Lichtenrade,13.396358,52.387706
-81,Lichterfelde Ost,13.328078,52.429098
-82,Lichterfelde Sued,13.308662,52.409956
-83,Lichterfelde West,13.294141,52.443512
-84,Mahlow,13.408775,52.360164
-85,Mahlsdorf,13.61123,52.512118
-86,Marienfelde,13.375022,52.423816
-87,Marzahn,13.541524,52.543272
-88,Mehrower Allee,13.554392,52.557816
-89,Messe Nord/ICC,13.283043,52.506454
-90,Messe Sued,13.27045,52.498771
-91,Mexikoplatz,13.23206,52.437166
-92,Muehlenbeck-Moenchmuehle,13.388224,52.654076
-93,Neuenhagen,13.699968,52.520852
-94,Neukoelln,13.443692,52.469282
-95,Nikolassee,13.193298,52.43121
-96,Nordbahnhof,13.388794,52.531673
-97,Noeldnerplatz,13.484297,52.503444
-98,Oberspree,13.538461,52.452269
-99,Olympiastadion,13.241111,52.511135
-100,Oranienburg,13.248432,52.754362
-101,Oranienburger Str.,13.393068,52.525161
-102,Osdorfer Str.,13.313865,52.418373
-103,Ostbahnhof,13.435747,52.510001
-104,Ostkreuz,13.469093,52.502851
-105,Pankow,13.412279,52.567281
-106,Pankow-Heinersdorf,13.42909,52.577603
-107,Petershagen Nord,13.790627,52.529185
-108,Pichelsberg,13.227196,52.510264
-109,Plaenterwald,13.474029,52.478722
-110,Poelchaustr.,13.536008,52.534751
-111,Potsdam Hauptbahnhof,13.067157,52.390931
-112,Potsdamer Platz,13.376454,52.50934
-113,Prenzlauer Allee,13.427419,52.544802
-114,Priesterweg,13.356028,52.459239
-115,Rahnsdorf,13.691655,52.451371
-116,Raoul-Wallenberg-Str.,13.548392,52.550749
-117,Rathaus Spandau,13.199891,52.535798
-118,Rathaus Steglitz,13.322473,52.455961
-119,Rummelsburg,13.478699,52.501213
-120,Roentgental,13.514302,52.649062
-121,Savignyplatz,13.319003,52.505223
-122,Schichauweg,13.389457,52.398563
-123,Schlachtensee,13.213986,52.439806
-124,Schulzendorf,13.24563,52.613513
-125,Schoeneberg,13.352848,52.479811
-126,Schoeneweide,13.510149,52.454611
-127,Schoenfliess,13.33888,52.66471
-128,Schoenhauser Allee,13.415138,52.549336
-129,Schoenholz,13.380242,52.571901
-130,Sonnenallee,13.455998,52.473822
-131,Spandau,13.197477,52.534798
-132,Spindlersfeld,13.562701,52.445938
-133,Springpfuhl,13.536904,52.525806
-134,Storkower Str.,13.464884,52.524195
-135,Strausberg,13.834793,52.532364
-136,Strausberg Nord,13.908894,52.5907
-137,Strausberg Stadt,13.888254,52.57745
-138,Stresow,13.20913,52.532505
-139,Sundgauer Str.,13.273501,52.436187
-140,Suedende,13.354077,52.448899
-141,Suedkreuz,13.365579,52.475468
-142,Tegel,13.288695,52.588805
-143,Teltow Stadt,13.275975,52.397147
-144,Tempelhof,13.385754,52.470694
-145,Tiergarten,13.336235,52.513963
-146,Treptower Park,13.460887,52.493022
-147,Waidmannslust,13.320549,52.606814
-148,Wannsee,13.179099,52.421457
-149,Warschauer Str.,13.448721,52.505889
-150,Wartenberg,13.504238,52.573266
-151,Wedding,13.36606,52.542732
-152,Westend,13.284237,52.51861
-153,Westhafen,13.343837,52.536183
-154,Westkreuz,13.283036,52.501152
-155,Wildau,13.633587,52.319205
-156,Wilhelmshagen,13.721004,52.438571
-157,Wilhelmsruh,13.363284,52.581588
-158,Wittenau,13.335481,52.596392
-159,Wollankstr.,13.39315,52.564974
-160,Wuhletal,13.575452,52.512465
-161,Wuhlheide,13.553527,52.469058
-162,Yorckstr. S1,13.369038,52.493034
-163,Yorckstr. S2 S25,13.371676,52.492608
-164,Zehlendorf,13.259227,52.431209
-165,Zepernick,13.533143,52.659218
-166,Zeuthen,13.626366,52.349441
-167,Zoologischer Garten,13.332707,52.506921
diff --git a/src/gurobi_optimods/data/graphs/uberlin_graph.json b/src/gurobi_optimods/data/graphs/uberlin_graph.json
new file mode 100644
index 00000000..d2a197c8
--- /dev/null
+++ b/src/gurobi_optimods/data/graphs/uberlin_graph.json
@@ -0,0 +1 @@
+{"directed": false, "multigraph": false, "graph": {}, "nodes": [{"pos": [13.448721, 52.505889], "id": 176}, {"pos": [13.441791, 52.501147], "id": 147}, {"pos": [13.428468, 52.499035], "id": 50}, {"pos": [13.417748, 52.499047], "id": 82}, {"pos": [13.406531, 52.498274], "id": 127}, {"pos": [13.39176, 52.497774], "id": 53}, {"pos": [13.383256, 52.498944], "id": 101}, {"pos": [13.374293, 52.499587], "id": 47}, {"pos": [13.362814, 52.49981], "id": 85}, {"pos": [13.353825, 52.499644], "id": 107}, {"pos": [13.342561, 52.502109], "id": 185}, {"pos": [13.331419, 52.503763], "id": 84}, {"pos": [13.326233, 52.502742], "id": 170}, {"pos": [13.412279, 52.567281], "id": 117}, {"pos": [13.41377, 52.559517], "id": 173}, {"pos": [13.415138, 52.549336], "id": 150}, {"pos": [13.41216, 52.541085], "id": 32}, {"pos": [13.412625, 52.532622], "id": 153}, {"pos": [13.410405, 52.528191], "id": 139}, {"pos": [13.411267, 52.521512], "id": 3}, {"pos": [13.412455, 52.517229], "id": 79}, {"pos": [13.408767, 52.512007], "id": 100}, {"pos": [13.402352, 52.511301], "id": 157}, {"pos": [13.395346, 52.513361], "id": 56}, {"pos": [13.389719, 52.511495], "id": 158}, {"pos": [13.383798, 52.511519], "id": 98}, {"pos": [13.376454, 52.50934], "id": 126}, {"pos": [13.374719, 52.503806], "id": 96}, {"pos": [13.362452, 52.497657], "id": 28}, {"pos": [13.332707, 52.506921], "id": 192}, {"pos": [13.322581, 52.511582], "id": 37}, {"pos": [13.30942, 52.511827], "id": 31}, {"pos": [13.305286, 52.511513], "id": 17}, {"pos": [13.297463, 52.51097], "id": 155}, {"pos": [13.281695, 52.509985], "id": 73}, {"pos": [13.272977, 52.509798], "id": 164}, {"pos": [13.25991, 52.516409], "id": 104}, {"pos": [13.2505, 52.517048], "id": 108}, {"pos": [13.241902, 52.525587], "id": 142}, {"pos": [13.336771, 52.500557], "id": 9}, {"pos": [13.330613, 52.496582], "id": 156}, {"pos": [13.324051, 52.493833], "id": 65}, {"pos": [13.314519, 52.490201], "id": 38}, {"pos": [13.311843, 52.479446], "id": 57}, {"pos": [13.314387, 52.472462], "id": 143}, {"pos": [13.309276, 52.467342], "id": 24}, {"pos": [13.295203, 52.464172], "id": 125}, {"pos": [13.290011, 52.457695], "id": 30}, {"pos": [13.281651, 52.451], "id": 167}, {"pos": [13.26891, 52.450419], "id": 113}, {"pos": [13.254016, 52.450146], "id": 109}, {"pos": [13.24036, 52.442615], "id": 83}, {"pos": [13.343264, 52.496169], "id": 172}, {"pos": [13.340237, 52.488654], "id": 10}, {"pos": [13.341989, 52.483332], "id": 130}, {"pos": [13.342875, 52.4781], "id": 68}, {"pos": [13.634541, 52.538105], "id": 67}, {"pos": [13.619707, 52.539135], "id": 92}, {"pos": [13.605794, 52.535946], "id": 59}, {"pos": [13.596894, 52.533963], "id": 29}, {"pos": [13.590777, 52.52824], "id": 105}, {"pos": [13.588763, 52.521436], "id": 77}, {"pos": [13.575452, 52.512465], "id": 186}, {"pos": [13.560762, 52.504643], "id": 35}, {"pos": [13.547326, 52.499517], "id": 15}, {"pos": [13.523626, 52.497236], "id": 168}, {"pos": [13.512791, 52.505895], "id": 44}, {"pos": [13.498228, 52.510754], "id": 89}, {"pos": [13.489439, 52.512214], "id": 93}, {"pos": [13.4753, 52.513613], "id": 39}, {"pos": [13.465347, 52.514662], "id": 144}, {"pos": [13.454085, 52.515772], "id": 40}, {"pos": [13.443278, 52.516848], "id": 177}, {"pos": [13.432208, 52.518025], "id": 161}, {"pos": [13.421895, 52.520316], "id": 146}, {"pos": [13.283821, 52.589649], "id": 5}, {"pos": [13.290122, 52.582139], "id": 22}, {"pos": [13.295083, 52.576252], "id": 66}, {"pos": [13.303074, 52.571122], "id": 116}, {"pos": [13.311524, 52.567111], "id": 145}, {"pos": [13.327328, 52.563483], "id": 86}, {"pos": [13.333502, 52.560862], "id": 2}, {"pos": [13.341013, 52.55667], "id": 134}, {"pos": [13.351969, 52.55047], "id": 152}, {"pos": [13.359395, 52.546493], "id": 88}, {"pos": [13.36606, 52.542732], "id": 178}, {"pos": [13.370393, 52.539895], "id": 135}, {"pos": [13.377033, 52.535397], "id": 149}, {"pos": [13.382415, 52.531254], "id": 102}, {"pos": [13.387587, 52.525163], "id": 112}, {"pos": [13.387153, 52.52027], "id": 45}, {"pos": [13.388876, 52.516996], "id": 196}, {"pos": [13.390863, 52.506673], "id": 80}, {"pos": [13.388153, 52.493575], "id": 94}, {"pos": [13.386351, 52.484977], "id": 124}, {"pos": [13.386725, 52.478142], "id": 121}, {"pos": [13.385754, 52.470694], "id": 163}, {"pos": [13.385796, 52.46593], "id": 6}, {"pos": [13.384905, 52.460512], "id": 74}, {"pos": [13.384771, 52.45345], "id": 171}, {"pos": [13.385561, 52.445801], "id": 182}, {"pos": [13.387456, 52.439641], "id": 4}, {"pos": [13.496734, 52.415614], "id": 141}, {"pos": [13.484371, 52.423032], "id": 193}, {"pos": [13.47482, 52.423152], "id": 187}, {"pos": [13.463109, 52.424645], "id": 91}, {"pos": [13.453851, 52.429253], "id": 71}, {"pos": [13.447668, 52.437076], "id": 25}, {"pos": [13.449925, 52.445344], "id": 122}, {"pos": [13.448976, 52.452743], "id": 18}, {"pos": [13.444828, 52.463516], "id": 49}, {"pos": [13.443692, 52.469282], "id": 106}, {"pos": [13.439805, 52.476429], "id": 76}, {"pos": [13.434807, 52.481146], "id": 128}, {"pos": [13.42472, 52.486957], "id": 60}, {"pos": [13.407685, 52.489219], "id": 162}, {"pos": [13.395382, 52.491252], "id": 48}, {"pos": [13.370429, 52.492766], "id": 188}, {"pos": [13.360917, 52.490845], "id": 78}, {"pos": [13.350276, 52.489529], "id": 34}, {"pos": [13.331355, 52.487047], "id": 13}, {"pos": [13.321618, 52.486347], "id": 19}, {"pos": [13.310084, 52.493567], "id": 81}, {"pos": [13.307348, 52.500086], "id": 1}, {"pos": [13.306885, 52.505834], "id": 183}, {"pos": [13.307221, 52.517154], "id": 137}, {"pos": [13.305715, 52.525978], "id": 97}, {"pos": [13.299064, 52.530275], "id": 72}, {"pos": [13.293661, 52.536985], "id": 69}, {"pos": [13.286578, 52.536703], "id": 52}, {"pos": [13.273323, 52.537026], "id": 154}, {"pos": [13.26287, 52.536904], "id": 138}, {"pos": [13.248593, 52.538098], "id": 123}, {"pos": [13.232309, 52.538718], "id": 55}, {"pos": [13.217625, 52.537522], "id": 191}, {"pos": [13.206763, 52.539161], "id": 7}, {"pos": [13.199891, 52.535798], "id": 131}, {"pos": [13.431704, 52.467181], "id": 63}, {"pos": [13.4284, 52.472874], "id": 87}, {"pos": [13.425782, 52.479745], "id": 21}, {"pos": [13.422241, 52.493179], "id": 151}, {"pos": [13.410947, 52.503739], "id": 99}, {"pos": [13.416169, 52.510858], "id": 58}, {"pos": [13.418027, 52.5155], "id": 70}, {"pos": [13.405305, 52.525376], "id": 179}, {"pos": [13.401393, 52.529781], "id": 140}, {"pos": [13.396231, 52.537994], "id": 14}, {"pos": [13.393157, 52.54193], "id": 174}, {"pos": [13.388372, 52.548637], "id": 46}, {"pos": [13.381837, 52.552255], "id": 118}, {"pos": [13.373284, 52.556938], "id": 115}, {"pos": [13.364283, 52.563854], "id": 41}, {"pos": [13.360635, 52.570843], "id": 136}, {"pos": [13.347532, 52.574534], "id": 119}, {"pos": [13.339047, 52.575394], "id": 90}, {"pos": [13.332921, 52.578169], "id": 75}, {"pos": [13.325568, 52.588218], "id": 129}, {"pos": [13.335481, 52.596392], "id": 184}, {"pos": [13.367365, 52.551524], "id": 103}, {"pos": [13.349534, 52.542202], "id": 8}, {"pos": [13.343837, 52.536183], "id": 181}, {"pos": [13.341417, 52.532229], "id": 16}, {"pos": [13.341417, 52.525938], "id": 169}, {"pos": [13.342165, 52.518111], "id": 54}, {"pos": [13.33121, 52.491992], "id": 51}, {"pos": [13.329149, 52.477366], "id": 26}, {"pos": [13.328676, 52.471439], "id": 43}, {"pos": [13.328409, 52.464998], "id": 175}, {"pos": [13.324836, 52.461183], "id": 148}, {"pos": [13.322152, 52.455066], "id": 132}, {"pos": [13.381937, 52.516511], "id": 23}, {"pos": [13.373454, 52.519908], "id": 27}, {"pos": [13.369075, 52.525605], "id": 11}, {"pos": [13.407061, 52.518462], "id": 194}, {"pos": [13.400394, 52.518086], "id": 195}], "links": [{"source": 176, "target": 147}, {"source": 147, "target": 50}, {"source": 50, "target": 82}, {"source": 82, "target": 127}, {"source": 82, "target": 151}, {"source": 82, "target": 99}, {"source": 127, "target": 53}, {"source": 53, "target": 101}, {"source": 53, "target": 80}, {"source": 53, "target": 94}, {"source": 101, "target": 47}, {"source": 101, "target": 94}, {"source": 101, "target": 188}, {"source": 47, "target": 85}, {"source": 47, "target": 96}, {"source": 47, "target": 28}, {"source": 85, "target": 107}, {"source": 107, "target": 185}, {"source": 107, "target": 28}, {"source": 107, "target": 172}, {"source": 185, "target": 84}, {"source": 185, "target": 192}, {"source": 185, "target": 9}, {"source": 84, "target": 170}, {"source": 84, "target": 192}, {"source": 84, "target": 156}, {"source": 117, "target": 173}, {"source": 173, "target": 150}, {"source": 150, "target": 32}, {"source": 32, "target": 153}, {"source": 153, "target": 139}, {"source": 139, "target": 3}, {"source": 3, "target": 79}, {"source": 3, "target": 146}, {"source": 3, "target": 70}, {"source": 3, "target": 179}, {"source": 3, "target": 194}, {"source": 79, "target": 100}, {"source": 100, "target": 157}, {"source": 157, "target": 56}, {"source": 56, "target": 158}, {"source": 158, "target": 98}, {"source": 158, "target": 196}, {"source": 158, "target": 80}, {"source": 98, "target": 126}, {"source": 126, "target": 96}, {"source": 192, "target": 37}, {"source": 192, "target": 54}, {"source": 37, "target": 31}, {"source": 31, "target": 17}, {"source": 17, "target": 155}, {"source": 17, "target": 183}, {"source": 17, "target": 137}, {"source": 155, "target": 73}, {"source": 73, "target": 164}, {"source": 164, "target": 104}, {"source": 104, "target": 108}, {"source": 108, "target": 142}, {"source": 9, "target": 156}, {"source": 156, "target": 65}, {"source": 156, "target": 51}, {"source": 65, "target": 38}, {"source": 38, "target": 57}, {"source": 38, "target": 19}, {"source": 38, "target": 81}, {"source": 57, "target": 143}, {"source": 143, "target": 24}, {"source": 24, "target": 125}, {"source": 125, "target": 30}, {"source": 30, "target": 167}, {"source": 167, "target": 113}, {"source": 113, "target": 109}, {"source": 109, "target": 83}, {"source": 172, "target": 10}, {"source": 10, "target": 130}, {"source": 10, "target": 34}, {"source": 10, "target": 13}, {"source": 130, "target": 68}, {"source": 67, "target": 92}, {"source": 92, "target": 59}, {"source": 59, "target": 29}, {"source": 29, "target": 105}, {"source": 105, "target": 77}, {"source": 77, "target": 186}, {"source": 186, "target": 35}, {"source": 35, "target": 15}, {"source": 15, "target": 168}, {"source": 168, "target": 44}, {"source": 44, "target": 89}, {"source": 89, "target": 93}, {"source": 93, "target": 39}, {"source": 39, "target": 144}, {"source": 144, "target": 40}, {"source": 40, "target": 177}, {"source": 177, "target": 161}, {"source": 161, "target": 146}, {"source": 5, "target": 22}, {"source": 22, "target": 66}, {"source": 66, "target": 116}, {"source": 116, "target": 145}, {"source": 145, "target": 86}, {"source": 86, "target": 2}, {"source": 2, "target": 134}, {"source": 134, "target": 152}, {"source": 152, "target": 88}, {"source": 88, "target": 178}, {"source": 88, "target": 103}, {"source": 88, "target": 8}, {"source": 178, "target": 135}, {"source": 135, "target": 149}, {"source": 149, "target": 102}, {"source": 102, "target": 112}, {"source": 112, "target": 45}, {"source": 45, "target": 196}, {"source": 196, "target": 23}, {"source": 196, "target": 195}, {"source": 94, "target": 124}, {"source": 94, "target": 48}, {"source": 124, "target": 121}, {"source": 121, "target": 163}, {"source": 163, "target": 6}, {"source": 6, "target": 74}, {"source": 74, "target": 171}, {"source": 171, "target": 182}, {"source": 182, "target": 4}, {"source": 141, "target": 193}, {"source": 193, "target": 187}, {"source": 187, "target": 91}, {"source": 91, "target": 71}, {"source": 71, "target": 25}, {"source": 25, "target": 122}, {"source": 122, "target": 18}, {"source": 18, "target": 49}, {"source": 49, "target": 106}, {"source": 106, "target": 76}, {"source": 76, "target": 128}, {"source": 128, "target": 60}, {"source": 60, "target": 162}, {"source": 60, "target": 21}, {"source": 60, "target": 151}, {"source": 162, "target": 48}, {"source": 188, "target": 78}, {"source": 78, "target": 34}, {"source": 13, "target": 19}, {"source": 13, "target": 51}, {"source": 13, "target": 26}, {"source": 81, "target": 1}, {"source": 1, "target": 183}, {"source": 137, "target": 97}, {"source": 97, "target": 72}, {"source": 72, "target": 69}, {"source": 69, "target": 52}, {"source": 52, "target": 154}, {"source": 154, "target": 138}, {"source": 138, "target": 123}, {"source": 123, "target": 55}, {"source": 55, "target": 191}, {"source": 191, "target": 7}, {"source": 7, "target": 131}, {"source": 63, "target": 87}, {"source": 87, "target": 21}, {"source": 99, "target": 58}, {"source": 58, "target": 70}, {"source": 179, "target": 140}, {"source": 140, "target": 14}, {"source": 14, "target": 174}, {"source": 174, "target": 46}, {"source": 46, "target": 118}, {"source": 118, "target": 115}, {"source": 115, "target": 41}, {"source": 115, "target": 103}, {"source": 41, "target": 136}, {"source": 136, "target": 119}, {"source": 119, "target": 90}, {"source": 90, "target": 75}, {"source": 75, "target": 129}, {"source": 129, "target": 184}, {"source": 8, "target": 181}, {"source": 181, "target": 16}, {"source": 16, "target": 169}, {"source": 169, "target": 54}, {"source": 26, "target": 43}, {"source": 43, "target": 175}, {"source": 175, "target": 148}, {"source": 148, "target": 132}, {"source": 23, "target": 27}, {"source": 27, "target": 11}, {"source": 194, "target": 195}]}
diff --git a/src/gurobi_optimods/data/graphs/uberlin_linepaths.csv b/src/gurobi_optimods/data/graphs/uberlin_linepaths.csv
new file mode 100644
index 00000000..067fc7eb
--- /dev/null
+++ b/src/gurobi_optimods/data/graphs/uberlin_linepaths.csv
@@ -0,0 +1,200 @@
+linename,edge_source,edge_target
+U1,176,147
+U1,147,50
+U1,50,82
+U1,82,127
+U1,127,53
+U1,53,101
+U1,101,47
+U1,47,85
+U1,85,107
+U1,107,185
+U1,185,84
+U1,84,170
+U2,117,173
+U2,173,150
+U2,150,32
+U2,32,153
+U2,153,139
+U2,139,3
+U2,3,79
+U2,79,100
+U2,100,157
+U2,157,56
+U2,56,158
+U2,158,98
+U2,98,126
+U2,126,96
+U2,96,47
+U2,47,28
+U2,28,107
+U2,107,185
+U2,185,192
+U2,192,37
+U2,37,31
+U2,31,17
+U2,17,155
+U2,155,73
+U2,73,164
+U2,164,104
+U2,104,108
+U2,108,142
+U3,176,147
+U3,147,50
+U3,50,82
+U3,82,127
+U3,127,53
+U3,53,101
+U3,101,47
+U3,47,85
+U3,85,107
+U3,107,185
+U3,185,9
+U3,9,156
+U3,156,65
+U3,65,38
+U3,38,57
+U3,57,143
+U3,143,24
+U3,24,125
+U3,125,30
+U3,30,167
+U3,167,113
+U3,113,109
+U3,109,83
+U4,107,172
+U4,172,10
+U4,10,130
+U4,130,68
+U5,67,92
+U5,92,59
+U5,59,29
+U5,29,105
+U5,105,77
+U5,77,186
+U5,186,35
+U5,35,15
+U5,15,168
+U5,168,44
+U5,44,89
+U5,89,93
+U5,93,39
+U5,39,144
+U5,144,40
+U5,40,177
+U5,177,161
+U5,161,146
+U5,146,3
+U5,3,194
+U5,194,195
+U5,195,196
+U5,196,23
+U5,23,27
+U5,27,11
+U6,5,22
+U6,22,66
+U6,66,116
+U6,116,145
+U6,145,86
+U6,86,2
+U6,2,134
+U6,134,152
+U6,152,88
+U6,88,178
+U6,178,135
+U6,135,149
+U6,149,102
+U6,102,112
+U6,112,45
+U6,45,196
+U6,196,158
+U6,158,80
+U6,80,53
+U6,53,94
+U6,94,124
+U6,124,121
+U6,121,163
+U6,163,6
+U6,6,74
+U6,74,171
+U6,171,182
+U6,182,4
+U7,141,193
+U7,193,187
+U7,187,91
+U7,91,71
+U7,71,25
+U7,25,122
+U7,122,18
+U7,18,49
+U7,49,106
+U7,106,76
+U7,76,128
+U7,128,60
+U7,60,162
+U7,162,48
+U7,48,94
+U7,94,101
+U7,101,188
+U7,188,78
+U7,78,34
+U7,34,10
+U7,10,13
+U7,13,19
+U7,19,38
+U7,38,81
+U7,81,1
+U7,1,183
+U7,183,17
+U7,17,137
+U7,137,97
+U7,97,72
+U7,72,69
+U7,69,52
+U7,52,154
+U7,154,138
+U7,138,123
+U7,123,55
+U7,55,191
+U7,191,7
+U7,7,131
+U8,63,87
+U8,87,21
+U8,21,60
+U8,60,151
+U8,151,82
+U8,82,99
+U8,99,58
+U8,58,70
+U8,70,3
+U8,3,179
+U8,179,140
+U8,140,14
+U8,14,174
+U8,174,46
+U8,46,118
+U8,118,115
+U8,115,41
+U8,41,136
+U8,136,119
+U8,119,90
+U8,90,75
+U8,75,129
+U8,129,184
+U9,115,103
+U9,103,88
+U9,88,8
+U9,8,181
+U9,181,16
+U9,16,169
+U9,169,54
+U9,54,192
+U9,192,84
+U9,84,156
+U9,156,51
+U9,51,13
+U9,13,26
+U9,26,43
+U9,43,175
+U9,175,148
+U9,148,132
diff --git a/src/gurobi_optimods/data/graphs/uberlin_reduced_graph.json b/src/gurobi_optimods/data/graphs/uberlin_reduced_graph.json
new file mode 100644
index 00000000..d04e3747
--- /dev/null
+++ b/src/gurobi_optimods/data/graphs/uberlin_reduced_graph.json
@@ -0,0 +1 @@
+{"directed": false, "multigraph": false, "graph": {}, "nodes": [{"pos": [13.428468, 52.499035], "id": 50}, {"pos": [13.417748, 52.499047], "id": 82}, {"pos": [13.406531, 52.498274], "id": 127}, {"pos": [13.39176, 52.497774], "id": 53}, {"pos": [13.383256, 52.498944], "id": 101}, {"pos": [13.411267, 52.521512], "id": 3}, {"pos": [13.412455, 52.517229], "id": 79}, {"pos": [13.408767, 52.512007], "id": 100}, {"pos": [13.402352, 52.511301], "id": 157}, {"pos": [13.395346, 52.513361], "id": 56}, {"pos": [13.389719, 52.511495], "id": 158}, {"pos": [13.421895, 52.520316], "id": 146}, {"pos": [13.387153, 52.52027], "id": 45}, {"pos": [13.388876, 52.516996], "id": 196}, {"pos": [13.390863, 52.506673], "id": 80}, {"pos": [13.388153, 52.493575], "id": 94}, {"pos": [13.386351, 52.484977], "id": 124}, {"pos": [13.434807, 52.481146], "id": 128}, {"pos": [13.42472, 52.486957], "id": 60}, {"pos": [13.407685, 52.489219], "id": 162}, {"pos": [13.395382, 52.491252], "id": 48}, {"pos": [13.425782, 52.479745], "id": 21}, {"pos": [13.422241, 52.493179], "id": 151}, {"pos": [13.410947, 52.503739], "id": 99}, {"pos": [13.416169, 52.510858], "id": 58}, {"pos": [13.418027, 52.5155], "id": 70}, {"pos": [13.381937, 52.516511], "id": 23}, {"pos": [13.407061, 52.518462], "id": 194}, {"pos": [13.400394, 52.518086], "id": 195}], "links": [{"source": 50, "target": 82}, {"source": 82, "target": 127}, {"source": 82, "target": 151}, {"source": 82, "target": 99}, {"source": 127, "target": 53}, {"source": 53, "target": 101}, {"source": 53, "target": 80}, {"source": 53, "target": 94}, {"source": 101, "target": 94}, {"source": 3, "target": 79}, {"source": 3, "target": 146}, {"source": 3, "target": 70}, {"source": 3, "target": 194}, {"source": 79, "target": 100}, {"source": 100, "target": 157}, {"source": 157, "target": 56}, {"source": 56, "target": 158}, {"source": 158, "target": 196}, {"source": 158, "target": 80}, {"source": 45, "target": 196}, {"source": 196, "target": 23}, {"source": 196, "target": 195}, {"source": 94, "target": 124}, {"source": 94, "target": 48}, {"source": 128, "target": 60}, {"source": 60, "target": 162}, {"source": 60, "target": 21}, {"source": 60, "target": 151}, {"source": 162, "target": 48}, {"source": 99, "target": 58}, {"source": 58, "target": 70}, {"source": 194, "target": 195}]}
diff --git a/src/gurobi_optimods/data/graphs/uberlin_reduced_linepaths.csv b/src/gurobi_optimods/data/graphs/uberlin_reduced_linepaths.csv
new file mode 100644
index 00000000..5ed60aa8
--- /dev/null
+++ b/src/gurobi_optimods/data/graphs/uberlin_reduced_linepaths.csv
@@ -0,0 +1,121 @@
+linename,edge_source,edge_target
+U1,147,50
+U1,50,82
+U1,82,127
+U1,127,53
+U1,53,101
+U1,101,47
+U1,85,107
+U1,185,84
+U2,173,150
+U2,32,153
+U2,139,3
+U2,3,79
+U2,79,100
+U2,100,157
+U2,157,56
+U2,56,158
+U2,158,98
+U2,126,96
+U2,47,28
+U2,107,185
+U2,192,37
+U2,31,17
+U2,155,73
+U2,164,104
+U2,108,142
+U3,147,50
+U3,50,82
+U3,82,127
+U3,127,53
+U3,53,101
+U3,101,47
+U3,85,107
+U3,185,9
+U3,156,65
+U3,38,57
+U3,143,24
+U3,125,30
+U3,167,113
+U3,109,83
+U4,172,10
+U4,130,68
+U5,92,59
+U5,29,105
+U5,77,186
+U5,35,15
+U5,168,44
+U5,89,93
+U5,39,144
+U5,40,177
+U5,161,146
+U5,146,3
+U5,3,194
+U5,194,195
+U5,195,196
+U5,196,23
+U5,23,27
+U6,22,66
+U6,116,145
+U6,86,2
+U6,134,152
+U6,88,178
+U6,135,149
+U6,102,112
+U6,112,45
+U6,45,196
+U6,196,158
+U6,158,80
+U6,80,53
+U6,53,94
+U6,94,124
+U6,124,121
+U6,163,6
+U6,74,171
+U6,182,4
+U7,193,187
+U7,91,71
+U7,25,122
+U7,18,49
+U7,106,76
+U7,76,128
+U7,128,60
+U7,60,162
+U7,162,48
+U7,48,94
+U7,94,101
+U7,101,188
+U7,78,34
+U7,10,13
+U7,19,38
+U7,81,1
+U7,183,17
+U7,137,97
+U7,72,69
+U7,52,154
+U7,138,123
+U7,55,191
+U7,7,131
+U8,87,21
+U8,21,60
+U8,60,151
+U8,151,82
+U8,82,99
+U8,99,58
+U8,58,70
+U8,70,3
+U8,3,179
+U8,140,14
+U8,174,46
+U8,118,115
+U8,41,136
+U8,119,90
+U8,75,129
+U9,103,88
+U9,8,181
+U9,16,169
+U9,54,192
+U9,84,156
+U9,51,13
+U9,26,43
+U9,175,148
diff --git a/src/gurobi_optimods/datasets.py b/src/gurobi_optimods/datasets.py
index f95a3e4d..7599c7ec 100644
--- a/src/gurobi_optimods/datasets.py
+++ b/src/gurobi_optimods/datasets.py
@@ -14,6 +14,13 @@
except ImportError:
nx = None
+try:
+ import json
+
+ from networkx.readwrite import json_graph
+except ImportError:
+ json = None
+
DATA_FILE_DIR = pathlib.Path(__file__).parent / "data"
@@ -56,19 +63,30 @@ def load_siouxfalls_network_data():
return (node_data, edge_data, line_data, linepath_data, demand_data)
-def load_sberlin_graph_data():
- # edge and node data to create a graph
- edge_data = pd.read_csv(DATA_FILE_DIR / "graphs/sberlin_edges.csv")
- node_data = pd.read_csv(DATA_FILE_DIR / "graphs/sberlin_nodes.csv")
+def load_metro_berlin_reduced_graph_data():
+ # read graph
+ with open(DATA_FILE_DIR / "graphs/uberlin_reduced_graph.json", "r") as f:
+ data = json.load(f)
+
+ # Convert the JSON data to a NetworkX graph
+ graph = json_graph.node_link_graph(data)
+
+ # line path data
+ linepath_data = pd.read_csv(DATA_FILE_DIR / "graphs/uberlin_reduced_linepaths.csv")
+
+ return (graph, linepath_data)
+
+
+def load_metro_berlin_graph_data():
+ # read graph
+ with open(DATA_FILE_DIR / "graphs/uberlin_graph.json", "r") as f:
+ data = json.load(f)
- # create graph
- graph = nx.from_pandas_edgelist(edge_data.reset_index(), create_using=nx.Graph())
- # add x-, y-coordinates as node attribute
- for number, row in node_data.set_index("number").iterrows():
- graph.add_node(number, pos=(row["posx"], row["posy"]))
+ # Convert the JSON data to a NetworkX graph
+ graph = json_graph.node_link_graph(data)
# line path data
- linepath_data = pd.read_csv(DATA_FILE_DIR / "graphs/sberlin_linepaths_sol.csv")
+ linepath_data = pd.read_csv(DATA_FILE_DIR / "graphs/uberlin_linepaths.csv")
return (graph, linepath_data)
diff --git a/src/gurobi_optimods/metromap.py b/src/gurobi_optimods/metromap.py
index 13446a95..435478d0 100644
--- a/src/gurobi_optimods/metromap.py
+++ b/src/gurobi_optimods/metromap.py
@@ -280,9 +280,16 @@ def create_model(
_create_direction_constraints(graph, model, edge_direction, x, y, mindist)
# define the bend for each two consecutive edges
- obj = _compute_bends(
- graph, model, edge_direction, obj, linepaths, penalty_line_bends, improve_lp
- )
+ if penalty_line_bends > 0:
+ obj = _compute_bends(
+ graph,
+ model,
+ edge_direction,
+ obj,
+ linepaths,
+ penalty_line_bends,
+ improve_lp,
+ )
if improve_lp:
# add some helpful constraints
@@ -642,7 +649,7 @@ def _compute_bends(
)
linExpr0bend += bend[w1, u1, w2, 0]
- if idx == 0 and improve_lp and linExpr0bend != 0:
+ if idx == 0 and improve_lp:
# this is a helpful cut but not necessary for the IP formulation
model.addConstr(linExpr0bend <= 1, name=f"bend_{v}")
return obj
@@ -1096,7 +1103,11 @@ def _plot_lines(graph, linepaths, directions):
xcoord = []
ycoord = []
for ut, vt in linepaths[l]:
- if ut not in G.nodes or vt not in G.nodes or (ut, vt) not in G.edges:
+ if (
+ ut not in graph.nodes
+ or vt not in graph.nodes
+ or (ut, vt) not in graph.edges
+ ):
raise ValueError(
f"linepath_data contain nodes or edges not contained in graph"
)