[PYTHON] Straßeninstallation durch Optimierung

Problem

Punkt(Knoten)Und Straßenkandidaten(Kante)In der Grafik bestehend aus
Stellen Sie eine Straße am Rand auf.
Ich möchte in der Lage sein, zwischen mehreren Knoten zu wechseln.
Die Gruppe von Knotensätzen, die Sie verschieben möchten, wird als Anforderung bezeichnet.
Komfort ist die Gesamtfahrstrecke, die die Nachfrage erfüllt.
Optimieren Sie die Installationskosten und den Komfort.

Sie können auch die Kombinationsoptimierung (http://qiita.com/SaitoTsutomu/items/bfbf4c185ed7004b5721) verwenden, um diese Probleme zu lösen.

Denkweise

Nur für Installationskosten Minimaler Gesamtflächenbaum in Typisches Problem 85% A8% E5% 9F% 9F% E6% 9C% A8) Problem oder [Steiner Tree](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%A5%E3% 82% BF% E3% 82% A4% E3% 83% 8A% E3% 83% BC% E6% 9C% A8) Dies ist ein Problem. Komfort allein ist eine Variante des typischen Problems, des Problems des minimalen Kostenflusses.

Durch Verringern der Installationskosten wird der Komfort verringert, und durch Erhöhen des Komforts werden die Installationskosten reduziert. Ein Optimierungsproblem mit mehreren Bewertungsskalen auf diese Weise wird als Mehrzweckoptimierungsproblem bezeichnet.

Hier finden Sie einen Kompromiss zwischen Installationskosten und Komfort. Zu diesem Zweck werden wir mathematische Probleme auf der Grundlage des Low-Mix-Problems mit minimalem Kostenfluss viele Male lösen und gleichzeitig die Installationskosten begrenzen.

Formulierung

$ \ mbox {Ziel} $ $ \ sum_i {\ sum_j {\ sum_k {x_ {ijk}}} $ Komfort
$ \ mbox {Variablen} $ $ x_ {ijk} \ ge 0 ~ \ für alle i, j, k $ Nachfrage Flussrate von Knoten j zu Knoten j in Bezug auf i
$ y_ {jk} \ in \ {0, 1 \} ~ \ forall j, k $ Gibt an, ob eine Straße zwischen Knoten j und Knoten k
$ \ mbox {vorbehaltlich} $ $ \ sum_ {j, k} {y_ {jk}} \ le Obergrenze $ Obergrenze der Installationskosten
$ x_ {ijk} \ le y_ {jk} ~ \ für alle i, j, k $ x Einschränkungen
$ \ sum_k {x_ {ijk}} = \ sum_k {x_ {ikj}} + Anforderung ~ \ für alle i, j $ Flussspeicher

Löse mit Python

Bereiten Sie vor, was Sie brauchen.

python


import random, numpy as np, pandas as pd, networkx as nx, matplotlib.pyplot as plt
from itertools import chain, combinations
from pulp import *

def draw(g):
    """Zeichnung"""
    nx.draw_networkx_labels(g, pos=pos)
    nx.draw_networkx_nodes(g, node_color='w', pos=pos)
    nx.draw_networkx_edges(g, pos=pos)
    plt.show()
def addvar(cnt=[0], *args, **kwargs):
    """Variablenerstellung"""
    cnt[0] += 1
    return LpVariable('v%d'%cnt[0], lowBound=0, *args, **kwargs)

Lassen Sie uns zufällig ein Problem erstellen. Die Nachfrage wurde nur zwischen einigen Knoten eingestellt.

python


n = 16 #Anzahl der Knoten
g = nx.random_graphs.fast_gnp_random_graph(n, 0.26, 8) #Graph
rn = g.nodes() #Knotenliste
pos = nx.spring_layout(g, pos={i:(i/4, i%4) for i in rn}) #Knotenposition
for i, j in g.edges():
    v = pos[i] - pos[j]
    g[i][j]['dist'] = np.sqrt(v.dot(v)) #Entfernung
dems = random.sample(list(combinations(rn, 2)), 10) #Nachfrage
draw(g)

image

Ich werde versuchen, den minimalen Gesamtflächenbaum zu finden.

python


h = nx.minimum_spanning_tree(g, 'dist')
draw(h)

image

Ich werde versuchen, es zu lösen.

python


rved = [(j, i) for i, j in g.edges()] #Rückseite
#Durchflussrate pro Bedarf
a = pd.DataFrame([(df, dt, ef, et, g.edge[ef][et]['dist'], addvar()) 
                  for df, dt in dems for ef, et in chain(g.edges(), rved)], 
                 columns=['DeFr', 'DeTo', 'EdFr', 'EdTo', 'Dist', 'Var'])
#Gibt an, ob eine Seite installiert werden soll
b = pd.DataFrame([(fr, to, g.edge[fr][to]['dist'], addvar(cat=LpBinary)) 
                  for fr, to in g.edges()], columns=['Fr', 'To', 'Dist', 'Var'])
res = [] #Lösung(Einrichtungskosten,Bequemlichkeit,Graph)
mxcst = 999 #Obergrenze für Installationskosten
while True:
    m = LpProblem() #Mathematisches Modell
    m += lpDot(a.Dist, a.Var) + lpDot(b.Dist, b.Var)*1e-6 #Zielfunktion(Bequemlichkeit)
    m += lpDot(b.Dist, b.Var) <= mxcst #Obergrenze für Installationskosten
    for _, r in a.iterrows():
        i, j = r.EdFr, r.EdTo
        if i > j: i, j = j, i
        #Installieren Sie, wenn der Durchfluss fließt
        m += r.Var <= lpSum(b.query('Fr==%s & To==%s'%(i,j)).Var)
    for (df, dt), c in a.groupby(('DeFr', 'DeTo')):
        for nd in rn:
            z = 1 if nd == df else -1 if nd == dt else 0
            #Flow-Speicher
            m += lpSum(c.query('EdFr == %s'%nd).Var) == \
                 lpSum(c.query('EdTo == %s'%nd).Var) + z
    m.solve() #Lösung
    if m.status != 1: break
    a['Val'] = a.Var.apply(lambda v: value(v)) #Ergebnis(Fließrate)
    b['Val'] = b.Var.apply(lambda v: value(v)) #Ergebnis(Ob installiert werden soll)
    cst = value(lpDot(b.Dist, b.Var)) #Einrichtungskosten
    val = value(m.objective) #Bequemlichkeit
    mxcst = cst - 1e-3 #Obergrenze für die nächsten Installationskosten
    h = nx.Graph()
    h.add_edges_from([(r.Fr, r.To) for _, r in b[b.Val == 1].iterrows()])
    res.append((cst, val, h))

Mal sehen, das Ergebnis. Je höher die Installationskosten sind, desto besser ist der Komfort.

python


plt.rcParams['font.family'] = 'IPAexGothic'
plt.plot([r[0] for r in res], [r[1] for r in res])
plt.xlabel('Einrichtungskosten')
plt.ylabel('Bequemlichkeit')

image

Dies ist die Grafik für den bequemsten Fall.

python


draw(res[0][2])

image

Ich habe versucht, eine GIF-Animation des Übergangs der Installationskosten zu erstellen. anim.gif

das ist alles

Recommended Posts