@@ -56,7 +56,8 @@ You may have to be within the university's network (or use VPN) for this.
## Tasks
* Model the BTSP as a Mixed Integer Program on paper.
* Implement the model with Gurobi.
* Model the BTSP as a Mixed Integer Program on paper. Use the [constraint technique](https://en.wikipedia.org/wiki/Travelling_salesman_problem#Dantzig%E2%80%93Fulkerson%E2%80%93Johnson_formulation) already used for SAT to enforce a single tour and do not use the [technique](https://en.wikipedia.org/wiki/Travelling_salesman_problem#Miller%E2%80%93Tucker%E2%80%93Zemlin_formulation[21]) used with CP-SAT (as it performs poorly with MIP-solvers).
* Implement the model with Gurobi. Add the subtour elimination constraints via callbacks.
* How does the solver performs compared to the CP-SAT-solver and the SAT-solver? What is the smallest instance you can no longer solve, and what is the largest instance you still can solve in 5 minutes.
* You can provide Gurobi with initial solutions. How does this influence the performance?
* Extend the solver to not just search for the minimal bottleneck, but return the shortest tour with this bottleneck. Also adapt your CP-SAT solver to do so and compare the performance of the two.
# Modeling of the Degree Constrained Bottleneck Spanning Tree with Mixed Integer Programming.
Wie auch schon bei SAT und CP wollen wir wieder das Problem*Degree Constrained Bottleneck Spanning Tree* als ausführliches Beispiel benutzen.
Allerdings erweitern wir das Problem diesmal wie folgt:
Unter allen Spannbäumen mit minimalem Bottleneck wollen wir einen Spannbaum finden, der das Gesamtgewicht aller Kanten minimiert.
As we did for [SAT](../../03_card_sat/DBST/) and [CP-SAT](../../02_cpsat/DBST), we again model the*Degree Constrained Bottleneck Spanning Tree* as an example.
However, we extend the problem as follows:
Among all spanning trees with minimal bottleneck, return the one with minimal weight (sum of weights of used edges).
Der Code ist wieder in Form eines Jupyter-Notebooks beigelegt.
Bitte bedenkt, dass wir den Code nur für die Lesbarkeit direkt im Jupyter-Notebook haben, Ihr den Code aber besser in einer separaten Python-Datei schreibt, da diese besser gemeinsam bearbeitet und wiederverwendet werden kann.
You can find the code again attached.
## Approach for the objective function
## Ansatz für die Zielfunktion
Despite the support of objective functions in Mixed Integer Programming, we cannot model the lexicographic objective directly.
We now have (at least) two options:
1. Use the minimum weight as objective and use a binary search as with SAT to find the minimum bottleneck.
2. Use a first Mixed Integer Program to find the minimum bottleneck, and then a separate one to find the minimum weight spanning tree in the restricted graph.
Obwohl IPs genau wie CPs die Minimierung einer Zielfunktion direkt unterstützen, können wir unsere zweiteilige Zielfunktion nicht direkt in einem IP modellieren.
Es gibt nun verschiedene mögliche Ansätze.
Wir könnten zum einen wie bei SAT eine binäre Suche nach dem optimalen Bottleneck durchführen.
Wir können aber auch ein erstes IP benutzen, um nach dem optimalen Bottleneck zu suchen, und dann in einem zweiten Schritt nach dem günstigsten Spannbaum mit dem gegebenen Bottleneck suchen.
Wir werden im Folgenden die zweite Möglichkeit nutzen; wir verwenden zuvor aber die bereits bei SAT verwendete Greedy-Heuristik, um eine obere Schranke an das Bottleneck zu finden.
Dann können wir von vornherein alle Kanten weglassen, die länger als dieses Bottleneck sind.
Das hilft uns dabei, möglichst wenige mögliche Kanten in unserem IP zu haben, und hat hoffentlich einen spürbaren positiven Einfluss auf die Lösungszeit.
We are going with the second approach, because based on my experience, I expect it to be much faster.
## Variablen und Nebenbedingungen
## Variables and Constraints
Wir führen für jede mögliche ungerichtete Kante $\{u,v\}$ eine Variable $x_{u,v} \in \mathbb{B}$ ein,
die genau dann den Wert 1 annehmen soll, wenn die Kante $\{u,v\}$ in unserem Spannbaum enthalten ist.
For every undirected edge, $\{u,v\}\in E$ we introduce a boolean variable $x_{u,v} \in \mathbb{B}$ that is $1$ if we use the edge, and $0$ otherwise.
Die Gradbeschränkung auf einen maximalen Grad von $d$ können wir dann für jeden Knoten $v$ als
The degree constraint of a maximal degree of $d$ can be expressed for every vertex $v\in V$ by
```equation
\sum\limits_{e \in \delta(\{v\})}x_e \leq d
\forall v\in V: \quad \sum\limits_{e \in \delta(\{v\})}x_e \leq d
```
realisieren.
Dabei ist $\delta(S)$ für eine Knotenmenge $S$ die Menge der Kanten, die einen Knoten $s \in S$ mit einem Knoten $t \in V \setminus S$ verbinden, also den ,,Rand'' der Menge $S$ überqueren.
Weiterhin muss
Here, $\delta(S)$ defines for a set of vertices $S\subset V$ the edges with one end in $S$ and one end in $V\setminus S$, thus, the edges leaving $S$.
Next let us enforce that every vertex has at least one neighbor (assuming that $|V|\geq 2$)
```equation
\sum\limits_{e \in \delta(\{v\})}x_e \geq 1
```
gelten, damit jeder Knoten wenigstens einen Nachbarn hat.
Wir fügen auch
As we want a tree, we additionally state
```equation
\sum\limits_{e \in E}x_e = n-1
```
als Bedingung hinzu.
Um den Zusammenhang sicherzustellen, verwenden wir diesmal die Möglichkeit, Lazy Constraints während der Suche einzufügen.
Wir fügen, ähnlich wie wir es bei SAT getan haben, für jede Teilmenge $\emptyset \neq S \subsetneq V$ die Nebenbedingung
The last, and most complicated constraint, is again enforcing the connectivity.
This can be done by the following set of constraints.
Dies stellt sicher, dass wenigstens eine Kante die Knoten der Menge $S$ mit den restlichen Knoten verbindet.
Da es insgesamt $\Theta(2^n)$ mögliche Teilmengen $S$ gibt, können wir diese Nebenbedingungen nicht alle auf einmal hinzufügen;
stattdessen untersuchen wir die bei der Suche gefundenen Lösungen und fügen nur Nebenbedingungen hinzu, die in diesen Lösungen verletzt sind.
As these are exponentially many, we add them via lazy constraints.
For this, we need to write a function that checks a solution if any of these constraints is violated.
We can do this efficiently by just looking at the connected components in the provided solution and add the constraint for every component (if there are more than one).
Note that while the set of constraints is exponential, we can derive the missing constraints in linear time (worst case, we have to do this exponentially often, but this rarely happens).
## Finding the minimum bottleneck
## Suche nach bestem Bottleneck
For finding the minimum bottleneck, we introduce an additional variable $\ell \in \mathbb{R}^+_0$, that represent the length of the longest edge.
The objective function can be expressed easily as
```equation
\min \ell
```
Wenn wir nach dem kleinsten möglichen Bottleneck suchen, führen wir die zusätzliche Variable $\ell$ ein, die die Länge der längsten Kante darstellen soll.
Die Zielfunktion ist in diesem Fall also $\min \ell$.
Um alle Kanten zu verbieten, die länger sind als $\ell$, verwenden wir für jede Kante $e$ die Nebenbedingung $\ell \geq c_ex_e$, wobei $c_e$ die Länge der Kante $e$ ist.
To prohibit all edges larger than $\ell$, we add for every edge the constraint
```equation
\forall e\in E: \ell \leq c_e \cdot x_e
```
where $c_e$ represents the length of the edge $e$.
## Suche nach optimalem Spannbaum
## Finding the minimum weight spanning tree
Nachdem wir das optimale Bottleneck $\ell^*$ gefunden haben, suchen wir nach dem Baum mit den geringsten Kosten,
indem wir das Problem ohne die Zielfunktionsvariable $\ell$ und ihre Nebenbedingungen lösen.
Dabei haben wir nur noch für die Kanten $e$ mit $c_e \leq \ell^*$ eine Kantenvariable; alle anderen Kanten dürfen wir nicht verwenden.
Als Zielfunktion verwenden wir $\min \sum_e c_ex_e$, also die Summe der Länge aller gewählten Kanten.
After we have determined $\ell$, we look for the spanning tree with the lowest weight on the edges that have at most the length $\ell$.
We can do so with nearly the same model, just delete $\ell$ and all $x_e$ with $c_e > \ell$.
Let $E'$ represent the remaining edges.
As objective function, we can use
```equation
\min \sum_{e\ in E'} c_e \cdot x_e
```
which is simply the sum of the weight of the used edges.