[PYTHON] Über das bestellte Patrouillenverkäuferproblem

Haben Sie jemals von der Frage des Handlungsreisenden gehört? Dies ist ein Problem, um die Schaltung zu finden, die die Pfadlänge zwischen den Schaltungen minimiert, die den Graphen mit einem einzigen Strich verfolgen können.

Dieses Mal möchte ich mich mit dem speziellen ** Problem der sequentiellen Bestellung ** unter den Problemen der reisenden Verkäufer befassen. (Ich kann keine japanische Übersetzung finden, daher habe ich sie entsprechend benannt. Wenn jemand sie kennt, lassen Sie es mich bitte wissen.)

Was sich vom ursprünglichen Problem des Handlungsreisenden unterscheidet, ist, dass es eine Bestellbeschränkung gibt, dass "dieser Punkt nach diesem Punkt gehen muss". Dies ermöglicht es, Situationen wie "Übergabe des von Herrn A an Herrn B erhaltenen Gepäcks" zu berücksichtigen.

Dieses Mal werden wir uns mit der Formulierung und den numerischen Versuchsergebnissen unter Verwendung des ganzzahligen Designs des sequentiellen Ordnungsproblems befassen.

Bereiten Sie zuerst die Symbole und Konstanten vor.

V :Punkt gesetzt, |V| := n \\
ss \in V :Startpunkt\\ 
E :Verzweigungssatz\\
c_{ij} ((v_i,v_j)\in E) :Ast(v_i,v_j)Kosten durchzugehen\\
\mathcal{S} = \{[v_i,v_j], \cdots\} :Ein Set mit einer Liste von zwei Punkten, die in Ordnung sein müssen

Definieren Sie als Nächstes die Variablen.

x_{ij} = 
\begin{cases}
    1 &Ast(v_i,v_j)Beim Durchfahren\\
    0 & otherwise
  \end{cases}\\
1\le u_{i} \le n-1 :Punkt v_Bestellung über i

Kommen wir nun zur Formulierung. Die Bedeutung jeder detaillierten Einschränkung wird später hinzugefügt.

\begin{eqnarray}
{minimize}& \sum_{(v_i,v_j)\in E}c_{ij}x_{ij} \\
subject \ to & \ \sum_{i} x_{ij} = 1 (\forall j) \\
&\sum_{j} x_{ij} = 1 (\forall i)\\
&u_i - u_j + (n-1)x_{ij} \le n-2 \ (\forall j \in S \setminus \{ss\}) \\
&u_{ss} = 0 \\
&u_{i} + 1 \le u_j \ (\forall (v_i,v_j) \in \mathcal{S})
\end{eqnarray}

Dies ist ein Implementierungsbeispiel. Ich machte eine zufällige Grafik und experimentierte.

sop.py


import pulp
import random
import networkx as nx
import math,time
import matplotlib.pyplot as plt

def make_random_graph(n):
    G = nx.DiGraph()
    for i in range(n):
        G.add_node(i,x=random.randint(0,10),y=random.randint(0,10))
    for i in range(n):
        for j in range(n):
            if i != j:
                dist = math.sqrt((G.nodes()[i]['x']-G.nodes()[j]['x'])**2 + (G.nodes()[i]['y']-G.nodes()[j]['y'])**2)
                G.add_edge(i,j,dist=dist)
    return G

def get_random_sequential_order(num_node,m):
    box = set()
    while len(box) < m:
        i = random.randint(0,num_node-2)
        j = random.randint(i+1,num_node-1)
        if (i,j) not in box:
            box.add((i,j))
    return box

def solve_SOP(G,precedense,num_node,ss):
    problem = pulp.LpProblem(name='SOP',sense=pulp.LpMinimize)
    x = {(i,j):pulp.LpVariable(cat="Binary",name=f"x_{i}_{j}") for (i,j) in G.edges()}
    u = {i:pulp.LpVariable(cat="Integer",name=f"u_{i}",lowBound=1,upBound=num_node-1) for i in G.nodes()}
    cost = {(i,j):G.adj[i][j]['dist'] for (i,j) in G.edges()}

    problem += pulp.lpSum([x[(i,j)]*cost[(i,j)] for (i,j) in G.edges()])


    for i in G.nodes():
        problem.addConstraint(pulp.lpSum([x[(i,j)] for j in range(num_node) if j != i]) == 1, f'outflow_{i}')
        problem.addConstraint(pulp.lpSum([x[(j,i)] for j in range(num_node) if j != i]) == 1, f'inflow_{i}')

    for i,j in G.edges():
        if i != ss and j != ss:
            problem.addConstraint(u[i]-u[j]+(num_node-1)*x[i,j] <= num_node-2, f'up_{i}_{j}')

    for i,j in precedense:
        problem.addConstraint(u[i]+1 <= u[j], f'sequential_{i}_{j}')

    u[ss] = 0

    print('start solving')
    start = time.time()
    status = problem.solve(pulp.CPLEX())
    # status = problem.solve()
    print(pulp.LpStatus[status])

    print(time.time()-start)

    if pulp.LpStatus[status] != 'Optimal':
        print('Infeasible!')
        exit()

    return x,u

def plot(G,x,u,precedense,ss):
    pos = {i: (G.nodes()[i]['x'], G.nodes()[i]['y']) for i in G.nodes()}
    nx.draw_networkx_nodes(G, pos, node_size=100, alpha=1, node_color='skyblue')
    edgelist = [e for e in G.edges() if x[e].value() > 0]
    nx.draw_networkx_edges(G, pos, edgelist=edgelist,width=3)
    precedense = [e for e in precedense]
    nx.draw_networkx_edges(G, pos, edgelist=precedense,edge_color='red')
    for i in G.nodes():
        if i != ss:
            plt.text(G.nodes()[i]['x'],G.nodes()[i]['y'],int(u[i].value()))
        else:
            plt.text(G.nodes()[i]['x'],G.nodes()[i]['y'],u[i])


    plt.show()

def main():
    num_node = 10
    num_precedence = 5
    ss = 0
    precedense = get_random_sequential_order(num_node,num_precedence)
    print(precedense)
    G = make_random_graph(num_node)
    x,u = solve_SOP(G,precedense,num_node,ss)
    plot(G,x,u,precedense,ss)

if __name__ == '__main__':
    main()

Es ist das Ausführungsergebnis mit 10 Punkten. Figure_1.png

Der schwarze Pfeil zeigt die Reihenfolge der Schaltung an, und der rote Pfeil zeigt die Reihenfolge der Präferenz an. Wenn die Anzahl der Punkte zunimmt, nimmt die Berechnungszeit exponentiell zu, so dass es bei der Verzweigungsbegrenzungsmethode, die die genaue Lösung der ganzzahligen Programmiermethode findet, streng zu sein scheint. Daher wurden ähnliche Lösungen für das ursprüngliche Problem des Handlungsreisenden vorgeschlagen.

Recommended Posts

Über das bestellte Patrouillenverkäuferproblem
Über das Problem der reisenden Verkäufer
Python: Ich habe das Problem des Handlungsreisenden ausprobiert
Lösen Sie das Problem des Handlungsreisenden mit OR-Tools
Ich habe versucht, das Problem des Handlungsreisenden umzusetzen
Denken Sie an das Problem der minimalen Änderung
Brennmethode und Problem mit reisenden Verkäufern
Ich habe Paizas Kampagnenproblem ausprobiert. (Rundschreiben Verkäufer Problem)
Über den Test
Versuchen Sie, das Problem des Handlungsreisenden mit einem genetischen Algorithmus zu lösen (Theorie)
Über die Warteschlange
Versuchen Sie, das Problem des Handlungsreisenden mit einem genetischen Algorithmus (Python-Code) zu lösen.
Versuchen Sie, das Problem des Handlungsreisenden mit einem genetischen Algorithmus zu lösen (Ausführungsergebnis)
Lösung des Problems des Handlungsreisenden mit dem genetischen Algorithmus (GA) und seiner Bibliothek (vcopt)
Lösen Sie das asymmetrische Python-Problem für reisende Verkäufer mit der Branch-and-Bound-Methode
Informationen zur Entfaltungsfunktion
Über den Servicebefehl
Über die Verwirrungsmatrix
Über das Besuchermuster
Untersuchen Sie das doppelte Problem
Eine Geschichte über den Umgang mit dem CORS-Problem
Über das Python-Modul venv
Über die Aufzählungsfunktion (Python)
Über das Verständnis des 3-Punkt-Lesers [...]
Über die Komponenten von Luigi
Über die Funktionen von Python
Kombinationsoptimierung - typisches Problem - Rundschreiben Verkäufer Problem
Ich habe versucht, "einen genetischen Algorithmus (GA) in Python zu implementieren, um das Problem des Handlungsreisenden (TSP) zu lösen".
Eine Geschichte, in der der Algorithmus zu einem lächerlichen Ergebnis kam, als er versuchte, das Problem der reisenden Verkäufer richtig zu lösen