Browse Source

added another document example

Martin Thoma 13 years ago
parent
commit
8deee55362

+ 107 - 0
documents/mathe-handlungsreisender/Handlungsreisender-in-Deutschland-Alle-Routen.py

@@ -0,0 +1,107 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" Dieses Script berechnet die Länge aller möglichen Routen und speichert sie
+    in "Entfernungen.txt". 
+    Am Ende wird noch die optimale Route ausgegeben. 
+
+    Benötigte Rechenzeit: ca. 50s """
+
+from copy import deepcopy
+
+# http://blog.bjrn.se/2008/04/lexicographic-permutations-using.html
+def next_permutation(seq, pred=cmp):
+    """Like C++ std::next_permutation() but implemented as
+    generator. Yields copies of seq."""
+    def reverse(seq, start, end):
+        # seq = seq[:start] + reversed(seq[start:end]) + \
+        #       seq[end:]
+        end -= 1
+        if end <= start:
+            return
+        while True:
+            seq[start], seq[end] = seq[end], seq[start]
+            if start == end or start+1 == end:
+                return
+            start += 1
+            end -= 1
+    if not seq:
+        raise StopIteration
+    try:
+        seq[0]
+    except TypeError:
+        raise TypeError("seq must allow random access.")
+    first = 0
+    last = len(seq)
+    seq = seq[:]
+    # Yield input sequence as the STL version is often
+    # used inside do {} while.
+    yield seq
+    if last == 1:
+        raise StopIteration
+    while True:
+        next = last - 1
+        while True:
+            # Step 1.
+            next1 = next
+            next -= 1
+            if pred(seq[next], seq[next1]) < 0:
+                # Step 2.
+                mid = last - 1
+                while not (pred(seq[next], seq[mid]) < 0):
+                    mid -= 1
+                seq[next], seq[mid] = seq[mid], seq[next]
+                # Step 3.
+                reverse(seq, next1, last)
+                # Change to yield references to get rid of
+                # (at worst) |seq|! copy operations.
+                yield seq[:]
+                break
+            if next == first:
+                raise StopIteration
+    raise StopIteration
+
+def Strecke_der_Route(Entfernungen, route):
+    """ Bestimmt die länge der Route und gibt diese als int zurück """
+    Entfernung = 0
+    for step, index in enumerate(route):
+        index2 = route[(step+1)%len(Entfernungen)]
+        Entfernung += Entfernungen[index][index2] # von index nach index2
+    return Entfernung
+
+def optimal_solution_with_brute_force(Entfernungen):
+    """ Findet die optimale Lösung, indem alle Routen durchgegangen werden.
+        Zurückgegeben wird eine Liste mit den Indizes """
+    liste = [i for i in xrange(0, len(Entfernungen))]
+    min_Entfernung_Route = [i for i in xrange(0, len(Entfernungen))]
+    min_Entfernung = Strecke_der_Route(Entfernungen, min_Entfernung_Route)
+    f = open('/home/moose/Entfernungen.txt', 'w')
+    for route in next_permutation(liste):
+        entfernung_tmp = Strecke_der_Route(Entfernungen, route)
+        f.write(str(entfernung_tmp) + "\n")
+        if entfernung_tmp < min_Entfernung:
+            min_Entfernung = entfernung_tmp
+            min_Entfernung_Route = deepcopy(route)
+    f.close()
+    return min_Entfernung_Route
+
+Stadtliste = ['Berlin', 'Hamburg', 'München', 'Köln', 'Frankfurt a. M.', 
+              'Stuttgart', 'Düsseldorf', 'Dortmund', 'Essen', 'Bremen']
+Entfernungen = []
+Entfernungen.append([  0, 288, 585, 575, 547, 633, 559, 494, 531, 392])
+Entfernungen.append([289,   0, 775, 426, 493, 655, 400, 344, 365, 122])
+Entfernungen.append([589, 775,   0, 577, 398, 220, 612, 604, 634, 748])
+Entfernungen.append([579, 426, 576,   0, 193, 369, 42,  95,   73, 320])
+Entfernungen.append([552, 492, 393, 193,   0, 210, 229, 219, 251, 445])
+Entfernungen.append([637, 667, 231, 369, 203,   0, 404, 417, 426, 642])
+Entfernungen.append([563, 408, 611,  38, 228, 404,   0,  71,  37, 302])
+Entfernungen.append([498, 346, 605,  95, 221, 418,  69,   0,  36, 240])
+Entfernungen.append([536, 374, 634,  74, 252, 427,  35,  37,   0, 267])
+Entfernungen.append([397, 123, 748, 315, 441, 638, 289, 233, 254,   0])
+
+print("Berechnung aller Routen wurde begonnen.")
+route = optimal_solution_with_brute_force(Entfernungen)
+print("Berechnung aller Routen wurde abgeschlossen.")
+print("Länge der optimalen Route: ", Strecke_der_Route(Entfernungen, route))
+for index in route:
+    print(Stadtliste[index])

+ 59 - 0
documents/mathe-handlungsreisender/Handlungsreisender-in-Deutschland-Nearest-Insertion.py

@@ -0,0 +1,59 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from copy import deepcopy
+
+def compute_length(Entfernungen, route):
+    """ Berechnet die Länge der Route und gibt diesen Integer zurück. """
+    entfernung = 0
+    for i in xrange(0, len(route)-1):
+        entfernung += Entfernungen[route[i]][route[i+1]]
+    return entfernung
+
+def nearest_insertion(Entfernungen):
+    """ Entfernungen: Entfernungen[x][y] gibt die Länge der Strecke von x nach
+                      y als integer an.
+        return: route als Liste, z.B. [0,3,4,1,2] 
+        Es wird immer mit der Stadt 0 begonnen. """
+    route = [0]
+    cities = len(Entfernungen)
+    maxEntfernung = max([item for sublist in Entfernungen for item in sublist])
+    aktuelleCity = 0
+    Entfernungen_read = deepcopy(Entfernungen)
+    for i in xrange(0, cities):
+        for sublist in Entfernungen:
+            sublist[aktuelleCity] = maxEntfernung + 1
+        aktuelleCity = Entfernungen[aktuelleCity].index( min(Entfernungen[aktuelleCity]) )
+        minInsert = None
+        routenLaenge = len(route)*(maxEntfernung+1)
+        for insertIndex in xrange(0, len(route) ):
+            route_tmp = deepcopy(route)
+            route_tmp.insert(insertIndex, aktuelleCity)
+            if compute_length(Entfernungen_read, route_tmp) < routenLaenge:
+                routenLaenge = compute_length(Entfernungen_read, route_tmp)
+                minInsert = insertIndex
+        route.insert(minInsert, aktuelleCity)
+        routenLaenge+= Entfernungen[route[-1]][aktuelleCity]
+
+    #Drehen der Route, sodass Berlin am Anfang und am Ende steht
+    route = route[route.index(0)+1:] + route[0:route.index(0)+1]
+
+    print("Routenlänge: %i" % compute_length(Entfernungen_read, route))
+    return route
+
+Entfernungen = []
+Entfernungen.append([  0, 288, 585, 575, 547, 633, 559, 494, 531, 392])
+Entfernungen.append([289,   0, 775, 426, 493, 655, 400, 344, 365, 122])
+Entfernungen.append([589, 775,   0, 577, 398, 220, 612, 604, 634, 748])
+Entfernungen.append([579, 426, 576,   0, 193, 369, 42,  95,   73, 320])
+Entfernungen.append([552, 492, 393, 193,   0, 210, 229, 219, 251, 445])
+Entfernungen.append([637, 667, 231, 369, 203,   0, 404, 417, 426, 642])
+Entfernungen.append([563, 408, 611,  38, 228, 404,   0,  71,  37, 302])
+Entfernungen.append([498, 346, 605,  95, 221, 418,  69,   0,  36, 240])
+Entfernungen.append([536, 374, 634,  74, 252, 427,  35,  37,   0, 267])
+Entfernungen.append([397, 123, 748, 315, 441, 638, 289, 233, 254,   0])
+Stadtliste = ['Berlin', 'Hamburg', 'München', 'Köln', 'Frankfurt a. M.', 
+              'Stuttgart', 'Düsseldorf', 'Dortmund', 'Essen', 'Bremen']
+
+for city in nearest_insertion(Entfernungen):
+    print("%s" % Stadtliste[city])

+ 72 - 0
documents/mathe-handlungsreisender/Handlungsreisender-in-Deutschland-analyse.py

@@ -0,0 +1,72 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" Dieses Script analysiert die Verteilung der Längen der Routen. Diese müssen
+    durch "Entfernungen.txt" gegeben sein. 
+
+    """
+
+print("Beginne alle Routen zu lesen.")
+f = open('/home/moose/mathe/Entfernungen.txt', 'r')
+lines = f.readlines()
+f.close()
+print("Alle Routen wurden eingelesen.")
+
+number = length = 0
+minimum= int(lines[0])
+maximum= int(lines[0])
+liste = []
+dict_entfernungen = {}
+for line in lines:
+    line = int(line)
+    if line in dict_entfernungen:
+        dict_entfernungen[line] += 1
+    else:
+        dict_entfernungen[line] = 1
+    liste.append(line)
+    number += 1
+    length += line
+    if line < minimum:
+        minimum = line
+    if line > maximum:
+        maximum = line
+print("Minimum: %i" % minimum)
+print("Maximum: %i" % maximum)
+print("Durchschnitt: %i" % (length/number))
+print("Anzahl der Routen: %i" % number)
+
+less_than2069 = 0.0
+for length, count in dict_entfernungen.items():
+    if length <= 2068:
+        less_than2069 += count
+
+print("maximale Abweichung von 5%%: %f %% aller Strecken" % (less_than2069/number*100))
+
+EntfernungsSet = set(liste)
+print("Anzahl der verschiedenen Streckenlängen: %i" % len(dict_entfernungen))
+
+import math, pylab
+
+x_list = []
+y_list = []
+for x, y in dict_entfernungen.items():
+    y_list.append(y)
+    x_list.append(x)
+
+pylab.xlabel("Streckenlange in km")
+pylab.ylabel("Anzahl der Routen")
+pylab.plot(x_list, y_list, 'b')
+
+# Einzeichnen des Durchschnitts:
+y_max = max(y_list)
+x_list = []
+y_list = []
+y_list.append(0)
+x_list.append((length/number))
+y_list.append(y_max)
+x_list.append((length/number))
+pylab.plot(x_list, y_list, 'r')
+
+pylab.savefig('Fig1.png')
+
+pylab.show()

+ 201 - 0
documents/mathe-handlungsreisender/Handlungsreisender-in-Deutschland.tex

@@ -0,0 +1,201 @@
+\documentclass[a4paper,9pt]{scrartcl}
+\usepackage[ngerman]{babel} 
+\usepackage[utf8]{inputenc}
+\usepackage{amssymb,amsmath}
+\usepackage{geometry}
+\usepackage{graphicx}
+\usepackage{hyperref}
+\usepackage{listings}
+\usepackage{color}
+
+\usepackage{slashbox}
+
+\definecolor{gray}{gray}{0.5}
+
+\lstset{
+language=Python,                % the language of the code
+basicstyle=\footnotesize,       % the size of the fonts that are used for the code
+keywordstyle=\color{blue},
+stringstyle=\color{red},
+commentstyle=\color{gray}\slshape,
+emph={class, pass, in, for, while, if, is, elif, else, not, and, or, def, print, exec, break, continue, return},
+emphstyle=\color{black}\bfseries,
+emph={[2]True, False, None, self},
+emph={[3]from, import, as},
+emphstyle=[3]\color{blue},
+morecomment=[s]{"""}{"""},
+rulesepcolor=\color{blue},
+otherkeywords={1, 2, 3, 4, 5, 6, 7, 8 ,9 , 0, -, =, +, [, ], (, ), \{, \}, :, *, !},
+numbers=left,                   % where to put the line-numbers
+numberstyle=\footnotesize,      % the size of the fonts that are used for the line-numbers
+stepnumber=1,                   % the step between two line-numbers. If it's 1, each line 
+                                % will be numbered
+numbersep=5pt,                  % how far the line-numbers are from the code
+showspaces=false,               % show spaces adding particular underscores
+showstringspaces=false,         % underline spaces within strings
+showtabs=false,                 % show tabs within strings adding particular underscores
+tabsize=2,                      % sets default tabsize to 2 spaces
+captionpos=b,                   % sets the caption-position to bottom
+breaklines=true,                % sets automatic line breaking
+breakatwhitespace=false,        % sets if automatic breaks should only happen at whitespace
+title=\lstname,                 % show the filename of files included with \lstinputlisting;
+                                % also try caption instead of title
+escapeinside={\%*}{*)},         % if you want to add a comment within your code
+morekeywords={*,...},           % if you want to add more keywords to the set
+literate=%
+{Ö}{{\"O}}1 
+{Ä}{{\"A}}1 
+{Ü}{{\"U}}1 
+{ß}{{\ss}}2 
+{ü}{{\"u}}1 
+{ä}{{\"a}}1 
+{ö}{{\"o}}1
+}
+
+\geometry{a4paper,left=18mm,right=18mm, top=1cm, bottom=2cm} 
+
+\setcounter{secnumdepth}{2}
+\setcounter{tocdepth}{2}
+
+\shorthandon{"}
+\hypersetup{
+    pdftitle={Handlungsreisender in Deutschland},
+    pdfsubject={Aufgabe},
+    pdfauthor={Martin Thoma},
+    pdfkeywords={Aufgabe, Mathematik, Lösung}}
+\shorthandoff{"}
+
+\begin{document}
+ \title{Handlungsreisender in Deutschland}
+ \author{Martin Thoma}
+
+
+ \setcounter{section}{1}
+ \section*{Aufgabenstellung}
+    Ein Handlungsreisender will seine Produkte in den zehn größten Städten 
+    Deutschlands verkaufen. Er startet in Berlin und will seine Reise dort 
+    beenden.
+
+    Die zehn einwohnerreichsten Städte Deutschlands sind Berlin, Hamburg, 
+    München, Köln, Frankfurt am Main, Stuttgart, Düsseldorf, Dortmund, Essen
+    und Bremen. \\
+    Folgende Tabelle gibt die Entfernung zwischen den Städten für eine Autoreise
+    wieder\footnote{Mit maps.google.com ermittelte Werte. Es wurde immer auf ganze Kilometer gerundet.}:
+
+    \begin{tabular}[hc]{|l|c|c|c|c|c|c|c|c|c|c|}
+      \hline
+      \backslashbox{von}{nach}  & \rotatebox{90}{Berlin} & \rotatebox{90}{Hamburg} & \rotatebox{90}{München} & \rotatebox{90}{Köln} & \rotatebox{90}{Frankfurt am Main} & \rotatebox{90}{Stuttgart} & \rotatebox{90}{Düsseldorf} & \rotatebox{90}{Dortmund} & \rotatebox{90}{Essen} & \rotatebox{90}{Bremen} \\
+      \hline\hline
+      Berlin    & 0     & 288   & 585   & 575   & 547   & 633   & 559   & 494   & 531   & 392 \\
+      Hamburg   & 289   & 0     & 775   & 426   & 493   & 655   & 400   & 344   & 365   & 122 \\
+      München   & 589   & 775   & 0     & 577   & 398   & 220   & 612   & 604   & 634   & 748 \\
+      Köln      & 579   & 426   & 576   & 0     & 193   & 369   & 42    & 95    & 73    & 320 \\
+      Frankfurt a. M.  & 552    & 492   & 393   & 193   & 0     & 210   & 229   & 219   & 251   & 445 \\
+      Stuttgart & 637   & 667   & 231   & 369   & 203   & 0     & 404   & 417   & 426   & 642 \\
+      Düsseldorf& 563   & 408   & 611   & 38    & 228   & 404   & 0     & 71    & 37    & 302 \\
+      Dortmund  & 498   & 346   & 605   & 95    & 221   & 418   & 69    & 0     & 36    & 240 \\
+      Essen     & 536   & 374   & 634   & 74    & 252   & 427   & 35    & 37    & 0     & 267 \\
+      Bremen    & 397   & 123   & 748   & 315   & 441   & 638   & 289   & 233   & 254   & 0   \\
+      \hline
+    \end{tabular}\\
+    \\
+    Welche Route sollte er wählen?
+
+  \subsection{Größenordnung des Problems}
+    Es gibt $9! = 9 \cdot 8 \cdot 7 \cdot 6 \cdot 5 \cdot 4 \cdot 3 \cdot 2 \cdot 1 = 362.880$ mögliche Routen,
+    da der Handlungsreisende in Berlin startet und 9 Möglichkeiten für die erste 
+    Stadt hat, 8 für die zweite, usw.\\
+    Allgemein kann man sagen, dass bei $n$ Städten insgesamt $(n-1)!$ mögliche 
+    Routen bestehen, da die Wahl des Startpunktes egal ist. \\
+    Falls das  Problem symmetrisch wäre, also die Strecke von Berlin nach 
+    München genauso lang wie die von München nach Berlin wäre, könnte man die
+    Anzahl der Routen auf $\frac{(n-1)!}{2}$ reduzieren. Allerdings ist das 
+    Problem offensichtlich asymmetrisch (siehe München $\rightarrow$ Berlin und 
+    München $\leftarrow$ Berlin)
+
+    Die Tabelle \ref{tab:functionGrowth} macht deutlich, wie schnell so etwas 
+    wächst.
+    \begin{table}[hc]
+        \centering
+        \begin{tabular}[hc]{|l|r|r|r|r|r|r|}
+          \hline
+          n         & $1$   & $log(n)$  & $n \cdot log(n)$  & $n^2$ & $n^3$ & $n!$  \\
+          \hline\hline
+          1         & 1     & 0         & 0                 & 1     &   1   & 1     \\
+          2         & 1     & 0,30      & 0,60              & 4     &   8   & 2     \\
+          3         & 1     & 0,48      & 1,43              & 9     &   27  & 6     \\
+          4         & 1     & 0,60      & 2,41              & 16    &   64  & 24    \\
+          5         & 1     & 0,70      & 3,49              & 25    &   125 & 120   \\
+          6         & 1     & 0,78      & 4,67              & 36    &   216 & 720   \\
+          7         & 1     & 0,85      & 5,92              & 49    &   343 & 5.040 \\
+          8         & 1     & 0,90      & 8,13              & 64    &   512 & 40.320\\
+          9         & 1     & 0,95      & 8,59              & 81    &   729 & 362.880\\
+         10         & 1     & 1,00      & 10,00             & 100   & 1.000 & 3.628.800\\
+         20         & 1     & 1,30      & 26,02             & 400   & 8.000 & $2,42 \cdot 10^{18}$ \\
+          \hline
+        \end{tabular}
+        \caption{Wachstum verschiedener Funktionen}
+        \label{tab:functionGrowth}
+    \end{table}
+  \newpage
+  \subsection{Intuitive Lösung}
+    Wenn man die Städte so auf der Karte sieht sollte man einfach mal die Route 
+    suchen, von der man denkt sie wäre gut. \\
+    \begin{center}
+    %\includegraphics{Germany_location_map.png}
+    \end{center}
+    Ich habe mir folgende ausgesucht:\\
+    \begin{center}
+    %\includegraphics{Germany_location_map-intuitiv.png}
+    \end{center}
+    Das ist die Route Berlin $\rightarrow$ München $\rightarrow$ Stuttgart 
+    $\rightarrow$ Frankfurt a. M. $\rightarrow$ Köln $\rightarrow$ Düsseldorf 
+    $\rightarrow$ Essen $\rightarrow$ Dortmund $\rightarrow$ Bremen 
+    $\rightarrow$ Hamburg $\rightarrow$ Berlin. 
+    Diese Route ist 1969 km lang. 
+
+  \newpage
+  \subsection{Optimale Lösung}
+  \subsubsection{Alle Routen durchgehen}
+    Die primitivste und langsamste Methode zum Finden der optimalen Lösung ist 
+    einfach alle möglichen Routen durch zu gehen. Dieser Algorithmus ist, was 
+    die Ausführungszeit angeht, in $\mathcal{O}(n!)$. Wie schnell diese wächst 
+    sollte mit Tabelle \ref{tab:functionGrowth} klar geworden sein.\\
+    Dieser Ansatz ist also nur für sehr kleine Instanzen des Problems geeignet.\\
+    \\
+    Eine Auswertung aller Stecken hat folgende Ergebnisse geliefert: \\
+    1969 km bzw. die von mir intuitiv gefundene Strecke ist eine von 10 optimalen Lösungen.\\
+    Die längste Route ist 4.913 km lang.\\
+    Es gibt 3.628.800 Routen, jedoch nur 2.597 verschiedene Streckenlängen. Die
+    durchschnittliche Streckenlänge beträgt 3.838 km und wurde rot eingezeichnet,
+    die maximale 4.913 km.\\
+    Die Verteilung der Streckenlängen sieht wie folgt aus:\\
+    %\includegraphics{Kurve.png}
+    \\
+    Würde man eine maximale Abweichung von $5\%$ akzeptieren, wären nur $0,002\%$
+    aller Routen akzeptabel. Durch eine zufällig gewählte Strecke wird man also 
+    kaum ein gutes Ergebnis erziehlen
+  \subsection{Heuristiken}
+    Eine Heuristik ist in diesem Zusammenhang ein vereinfachtes Verfahren, das 
+    keine optimale Lösung liefert, aber eine akzeptable Näherung daran. Dafür 
+    ist die Heuristik deutlich schneller.\\
+  \subsubsection{Nächster Nachbar}
+    Eine mögliche Heurisik ist das auswählen der Stadt, die am nächsten zur 
+    aktuellen Stadt liegt. Mit diesem Verfahren erhält man bei der gegebenen 
+    Städtekonstellation eine Route der Länge 2.162 km. Das sind 193 km oder 
+    $9,8\%$ mehr als die optimale Lösung benötigt.
+
+  \subsubsection{Nächster Nachbar - Dynamisch Einfügen}
+    Die Methode des nächsten Nachbars kann verbessert werden, indem der Nachbar 
+    nicht einfach am Ende in die Route eingefügt wird, sondern an die Stelle, an 
+    der die resultierende Route am kleinsten wäre. Damit erhält man bei der 
+    gegebenen Städtekonstellation eine optimale Route.
+
+  \newpage
+    \lstinputlisting[language=Python]{Handlungsreisender-in-Deutschland-Alle-Routen.py}
+  \newpage
+    \lstinputlisting[language=Python]{Handlungsreisender-in-Deutschland-analyse.py}
+  \newpage
+    %\lstinputlisting[language=Python]{Handlungsreisender-in-Deutschland-Nearest-Neighbour.py}
+    \lstinputlisting[language=Python]{Handlungsreisender-in-Deutschland-Nearest-Insertion.py}
+\end{document}

+ 6 - 0
documents/mathe-handlungsreisender/Makefile

@@ -0,0 +1,6 @@
+make:
+	pdflatex Handlungsreisender-in-Deutschland.tex -output-format=pdf
+	make clean
+
+clean:
+	rm -rf  $(TARGET) *.class *.html *.log *.aux *.out

+ 77 - 0
documents/mathe-handlungsreisender/slashbox.sty

@@ -0,0 +1,77 @@
+% slashbox.sty by Koichi Yasuoka, May 27, 1993
+%              minor modification by Toru Sato, May 31, 1993
+\typeout{slashbox style by K.Yasuoka, May 1993.}%
+\newbox\@slashboxa
+\newbox\@slashboxb
+\newbox\@slashboxc
+\newcount\@slashboxwd
+\newcount\@slashboxht
+\newdimen\@slashsepl
+\newdimen\@slashsepr
+\def\slashbox{%
+  \def\@slashboxpicture##1{%
+    \put(0,0){\line(##1,1){\@slashboxwd}}%
+    \put(0,\@slashboxht){\makebox(0,0)[tl]{\box\@slashboxa}}%
+    \put(\@slashboxwd,0){\makebox(0,0)[br]{\box\@slashboxb}}%
+  }%
+  \@slashbox
+}%
+\def\backslashbox{%
+  \def\@slashboxpicture##1{%
+    \put(0,\@slashboxht){\line(##1,-1){\@slashboxwd}}%
+    \put(0,0){\makebox(0,0)[bl]{\box\@slashboxa}}%
+    \put(\@slashboxwd,\@slashboxht){\makebox(0,0)[tr]{\box\@slashboxb}}%
+  }%
+  \@slashbox
+}%
+\def\@slashbox{\@ifnextchar [{\@@slashbox}{\@@slashbox[0pt]}}
+\def\@@slashbox[#1]{\@ifnextchar [{\@@@slashbox[#1]}{\@@@slashbox[#1][c]}}
+\def\@@@slashbox[#1][#2]#3#4{%
+% #1: width, #2: suppression of \tabcolsep on `l', `r', or `lr' side
+% #3: left item, #4: right item
+  \@slashsepl=\tabcolsep
+  \@slashsepr=\tabcolsep
+    \@tfor\@tempa :=#2\do{\expandafter\let
+        \csname @slashsep\@tempa\endcsname=\z@}%
+  \setbox\@slashboxa=\hbox{\strut\hskip\tabcolsep\shortstack[l]{#3}}%
+  \setbox\@slashboxb=\hbox{\shortstack[r]{#4}\hskip\tabcolsep\strut}%
+  \setbox\@slashboxa=\hbox{\raise\dp\@slashboxa\box\@slashboxa}%
+  \setbox\@slashboxb=\hbox{\raise\dp\@slashboxb\box\@slashboxb}%
+  \setbox\@slashboxc=\hbox{%
+    \@tempdima=\wd\@slashboxa
+    \advance\@tempdima by \wd\@slashboxb
+    \advance\@tempdima by \@slashsepl
+    \advance\@tempdima by \@slashsepr
+    \@tempdimb=#1\relax%
+    \ifdim\@tempdimb>\@tempdima \@tempdima=\@tempdimb\fi%
+    \@tempdimb=\ht\@slashboxa
+    \advance\@tempdimb by \dp\@slashboxa
+    \advance\@tempdimb by \ht\@slashboxb
+    \advance\@tempdimb by \dp\@slashboxb
+    \@tempcnta=\@tempdima
+    \@tempcntb=\@tempdimb
+    \advance\@tempcnta by \@tempcntb
+    \advance\@tempcnta by -1
+    \divide\@tempcnta by \@tempcntb
+    \ifnum\@tempcnta>6 \@tempcnta=6
+      \@tempdimb=0.166666666\@tempdima
+    \else
+      \ifnum\@tempcnta<1 \@tempcnta=1\fi
+      \@tempdima=\@tempdimb
+      \multiply\@tempdima by \@tempcnta
+    \fi%
+    \advance\@tempdima by -\@slashsepl
+    \advance\@tempdima by -\@slashsepr
+    \@slashboxwd=\@tempdima
+    \@slashboxht=\@tempdimb
+    \@tempcntb=\@slashsepl
+    \setlength{\unitlength}{1sp}%
+    \begin{picture}(\@slashboxwd,\@slashboxht)(\@tempcntb,0)
+    \advance\@tempdima by \@slashsepl
+    \advance\@tempdima by \@slashsepr
+    \@slashboxwd=\@tempdima
+    \@slashboxpicture{\@tempcnta}
+    \end{picture}%
+  }%
+  $\vcenter{\box\@slashboxc}$%
+}%