
Hallo Python Community,
bin neu in der Liste und hab natürlich gleich eine Frage. Ich versuche den dijkstra algorithmus in Python zu implementieren. Gegeben sind zwei Dateien: die network.txt die die distanzen der einzelnen nodes angibt und die route.txt die mir anfangs und endpunkt ausgibt.
Beispiel network.txt (in diesem Beispiel nodes A-G): 0,2,4,1,6,0,0 2,0,0,0,5,0,0 4,0,0,0,0,5,0 1,0,0,0,1,1,0 6,5,0,1,0,5,5 0,0,5,1,5,0,0 0,0,0,0,5,0,0
Beispiel route.txt: B>F
Am ende soll eine neue txt datei erstellt werden welche die route und die total path length enthält.
Bis auf den letzten Schritt funktioniert auch alles soweit (python 3.1.1). Ich bin nur noch nicht dahinter gekommen wie ich am Ende am besten die Route und die Total path length berechne. Hatte überlegt den weg vom letzten zum ersten node einfach zurückzugehen aber das scheint mir umständlich und kompliziert.
Hier das script soweit ich das hinbekommen habe:
import sys
invalid_node = -1
class Node: previous = invalid_node distFromSource = sys.maxsize visited = False
#print ("\nReading the file into a list.") txtfile = open("network.txt", "r") numberOfNodes = 0
network = [] # array containing array of values for each line
# reading file line by line for line in txtfile: # increment nodeCount numberOfNodes += 1
# remove end chars line = line.replace("\n","") line = line.replace("\r","")
# split by comma chars = line.split(",") ints = []
# convert string to int for char in chars: ints.append(int(char))
# append the list of ints to the array network.append(ints)
# read start (dist value = 0) and end node route = open("route.txt", "r")
for line in route: nodes = line.split(">") startNode = nodes[0] endNode = nodes[1]
# get the ascii value and minus 65 startNode =(ord(startNode) - 65) endNode =(ord(endNode) - 65)
#print ("Start node: " + str(startNode)) #print ("End node: " + str(endNode))
# set currentNode to startNode currentNode = startNode
# create another 2d array with previous node, distFromSource and visited # use sys.maxint for distFromSource
nodeTable = [] # array containing nodeTable visited/unvisited,prevNode and distFromSrc i = 0
while i <= numberOfNodes: nodeTable.append(Node()) i += 1
# set distFromSource of startNode to 0 nodeTable[startNode].distFromSource = 0 nodeTable[startNode].visited = True
#write a function to find the neighbour of current node def findNeighbours(currentNode): # find nearest neighbour of currentNode currentRow = network[currentNode] currentNeighbours = [] i = 0
for distance in currentRow: #get back the index number / position if distance = 0 if distance != 0: #save the location currentNeighbours.append(i) i += 1 return currentNeighbours
#print ("\nCurrent Neighbours (of node " + str(currentNode) + "): ") currentNeighbours = findNeighbours(currentNode)
#print (currentNeighbours)
# go through currentNeighbour and see if they have been visited or not # set dustFromSource and previousNode for unvisited def checkNeighbours(): for neighbour in currentNeighbours: if nodeTable[neighbour].visited == True: pass #print ("True") else: # calculate their tentative distances from starting node # add distFromSource from currentNode with distance between currentNode and neighbour # check if less than current newDistance = nodeTable[currentNode].distFromSource + network[currentNode][neighbour]
if (nodeTable[neighbour].distFromSource > newDistance): nodeTable[neighbour].distFromSource = newDistance nodeTable[neighbour].previous = currentNode
checkNeighbours() #printNodeTb()
# go through all distances of unvisited, find lowest and mark as visited def setNewCurrentNode(): global currentNode index = 0 currentDist = sys.maxsize
for node in nodeTable: if node.visited == False and node.distFromSource < currentDist: currentNode = index currentDist = node.distFromSource index+=1
nodeTable[currentNode].visited = True print ("\nNew Current Node: " + str(currentNode))
setNewCurrentNode()
#total path length tpl = 0
f = open("09023429spf.txt", "w") f.write(str(chr(startNode+65)))
# check if destination node reached while currentNode != endNode:
#print ("\nCurrent Neighbours (of node " + str(currentNode) + "): ") currentNeighbours = findNeighbours(currentNode) #print (currentNeighbours)
checkNeighbours() f.write(str(chr(currentNode+65)))
setNewCurrentNode() #add total path length tpl += nodeTable[nodeTable[currentNode].previous].distFromSource
f.write(str(chr(endNode+65))) f.write(" " + str(tpl)) f.close()
print ("\nTotal path length: " + str(tpl) + "\n") for node in nodeTable: print (str(node.previous) + " | " + str(node.distFromSource) + " | " + str(node.visited))
Wäre für jede Hilfe dankbar.
Dankeschön.
Gruß Andi

Hallo Andi,
Schau dir mal die networkx Library an http://networkx.lanl.gov/ . Diese Lib hat viele Funktionen zur Graphen Berechnung.
Lg, Chris
Von meinem iPad gesendet
Am 18.02.2012 um 18:16 schrieb sackbard sackbard@googlemail.com:
Hallo Python Community,
bin neu in der Liste und hab natürlich gleich eine Frage. Ich versuche den dijkstra algorithmus in Python zu implementieren. Gegeben sind zwei Dateien: die network.txt die die distanzen der einzelnen nodes angibt und die route.txt die mir anfangs und endpunkt ausgibt.
Beispiel network.txt (in diesem Beispiel nodes A-G): 0,2,4,1,6,0,0 2,0,0,0,5,0,0 4,0,0,0,0,5,0 1,0,0,0,1,1,0 6,5,0,1,0,5,5 0,0,5,1,5,0,0 0,0,0,0,5,0,0
Beispiel route.txt: B>F
Am ende soll eine neue txt datei erstellt werden welche die route und die total path length enthält.
Bis auf den letzten Schritt funktioniert auch alles soweit (python 3.1.1). Ich bin nur noch nicht dahinter gekommen wie ich am Ende am besten die Route und die Total path length berechne. Hatte überlegt den weg vom letzten zum ersten node einfach zurückzugehen aber das scheint mir umständlich und kompliziert.
Hier das script soweit ich das hinbekommen habe:
import sys
invalid_node = -1
class Node: previous = invalid_node distFromSource = sys.maxsize visited = False
#print ("\nReading the file into a list.") txtfile = open("network.txt", "r") numberOfNodes = 0
network = [] # array containing array of values for each line
# reading file line by line for line in txtfile: # increment nodeCount numberOfNodes += 1
# remove end chars line = line.replace("\n","") line = line.replace("\r","")
# split by comma chars = line.split(",") ints = []
# convert string to int for char in chars: ints.append(int(char))
# append the list of ints to the array network.append(ints)
# read start (dist value = 0) and end node route = open("route.txt", "r")
for line in route: nodes = line.split(">") startNode = nodes[0] endNode = nodes[1]
# get the ascii value and minus 65 startNode =(ord(startNode) - 65) endNode =(ord(endNode) - 65)
#print ("Start node: " + str(startNode)) #print ("End node: " + str(endNode))
# set currentNode to startNode currentNode = startNode
# create another 2d array with previous node, distFromSource and visited # use sys.maxint for distFromSource
nodeTable = [] # array containing nodeTable visited/unvisited,prevNode and distFromSrc i = 0
while i <= numberOfNodes: nodeTable.append(Node()) i += 1
# set distFromSource of startNode to 0 nodeTable[startNode].distFromSource = 0 nodeTable[startNode].visited = True
#write a function to find the neighbour of current node def findNeighbours(currentNode): # find nearest neighbour of currentNode currentRow = network[currentNode] currentNeighbours = [] i = 0
for distance in currentRow: #get back the index number / position if distance = 0 if distance != 0: #save the location currentNeighbours.append(i) i += 1 return currentNeighbours
#print ("\nCurrent Neighbours (of node " + str(currentNode) + "): ") currentNeighbours = findNeighbours(currentNode)
#print (currentNeighbours)
# go through currentNeighbour and see if they have been visited or not # set dustFromSource and previousNode for unvisited def checkNeighbours(): for neighbour in currentNeighbours: if nodeTable[neighbour].visited == True: pass #print ("True") else: # calculate their tentative distances from starting node # add distFromSource from currentNode with distance between currentNode and neighbour # check if less than current newDistance = nodeTable[currentNode].distFromSource + network[currentNode][neighbour]
if (nodeTable[neighbour].distFromSource > newDistance): nodeTable[neighbour].distFromSource = newDistance nodeTable[neighbour].previous = currentNode
checkNeighbours() #printNodeTb()
# go through all distances of unvisited, find lowest and mark as visited def setNewCurrentNode(): global currentNode index = 0 currentDist = sys.maxsize
for node in nodeTable: if node.visited == False and node.distFromSource < currentDist: currentNode = index currentDist = node.distFromSource index+=1
nodeTable[currentNode].visited = True print ("\nNew Current Node: " + str(currentNode))
setNewCurrentNode()
#total path length tpl = 0
f = open("09023429spf.txt", "w") f.write(str(chr(startNode+65)))
# check if destination node reached while currentNode != endNode:
#print ("\nCurrent Neighbours (of node " + str(currentNode) + "): ") currentNeighbours = findNeighbours(currentNode) #print (currentNeighbours)
checkNeighbours() f.write(str(chr(currentNode+65)))
setNewCurrentNode() #add total path length tpl += nodeTable[nodeTable[currentNode].previous].distFromSource
f.write(str(chr(endNode+65))) f.write(" " + str(tpl)) f.close()
print ("\nTotal path length: " + str(tpl) + "\n") for node in nodeTable: print (str(node.previous) + " | " + str(node.distFromSource) + " | "
- str(node.visited))
Wäre für jede Hilfe dankbar.
Dankeschön.
Gruß Andi
python-de maillist - python-de@python.org http://mail.python.org/mailman/listinfo/python-de

sackbard wrote:
Hallo Python Community,
bin neu in der Liste und hab natürlich gleich eine Frage. Ich versuche den dijkstra algorithmus in Python zu implementieren. Gegeben sind zwei Dateien: die network.txt die die distanzen der einzelnen nodes angibt und die route.txt die mir anfangs und endpunkt ausgibt.
Beispiel network.txt (in diesem Beispiel nodes A-G): 0,2,4,1,6,0,0 2,0,0,0,5,0,0 4,0,0,0,0,5,0 1,0,0,0,1,1,0 6,5,0,1,0,5,5 0,0,5,1,5,0,0 0,0,0,0,5,0,0
Beispiel route.txt: B>F
Am ende soll eine neue txt datei erstellt werden welche die route und die total path length enthält.
Bis auf den letzten Schritt funktioniert auch alles soweit (python 3.1.1). Ich bin nur noch nicht dahinter gekommen wie ich am Ende am besten die Route und die Total path length berechne. Hatte überlegt den weg vom letzten zum ersten node einfach zurückzugehen aber das scheint mir umständlich und kompliziert.
So kompliziert auch wieder nicht:
currentNode = endNode route = [] while True: route.append(currentNode) if currentNode == startNode: break currentNode = nodeTable[currentNode].previous route.reverse() print(">".join(chr(node+65) for node in route))
Wenn ich dein Script richtig verstehe, hast du die "total path length" doch schon als Node.distFromSource gespeichert.
Noch ein paar Empfehlungen zu deinem Code:
Du mischst Code-Schnipsel und Funktionsdefinitionen wild durcheinander. Ich empfehle, die Funktionen an den Anfang zu stellen und die "Schnipsel" alle zusammen in eine Funktion zu packen. Damit vermeidest du unnötige globale Variablen.
Hier das script soweit ich das hinbekommen habe:
import sys
invalid_node = -1
class Node: previous = invalid_node distFromSource = sys.maxsize visited = False
Das geht hier zwar, weil alle Klassenattribute "immutable" sind, aber eine __init__()-Methode wär sauberer. Ich würde auch Namen und Index des Knotens speichern.
#print ("\nReading the file into a list.") txtfile = open("network.txt", "r") numberOfNodes = 0
network = [] # array containing array of values for each line
In neuerem Python-Code verwendet man
with open(...) as file: # use it
statt
file = open(...) # use it file.close()
# reading file line by line for line in txtfile: # increment nodeCount numberOfNodes += 1
# remove end chars line = line.replace("\n","") line = line.replace("\r","") # split by comma chars = line.split(",") ints = [] # convert string to int for char in chars: ints.append(int(char)) # append the list of ints to the array network.append(ints)
Als list-comprehension: network = [ [int(s) for s in line.split(",")] for line in txtfile ]
Zeilenenden vorher zu entfernen is überflüssig, da int() "whitespace" ignoriert:
int(" 123\n")
123
# read start (dist value = 0) and end node route = open("route.txt", "r")
for line in route: nodes = line.split(">") startNode = nodes[0] endNode = nodes[1]
# get the ascii value and minus 65 startNode =(ord(startNode) - 65) endNode =(ord(endNode) - 65)
#print ("Start node: " + str(startNode)) #print ("End node: " + str(endNode))
# set currentNode to startNode currentNode = startNode
# create another 2d array with previous node, distFromSource and visited # use sys.maxint for distFromSource
nodeTable = [] # array containing nodeTable visited/unvisited,prevNode and distFromSrc i = 0
while i <= numberOfNodes:
Du erstellst numberOfNodes+1 Node-Instanzen. Ist das Absicht?
nodeTable.append(Node()) i += 1
Indices werden in Python selten manuell verwaltet. Entweder:
for i in range(len(network)): nodeTable.append(Node())
oder:
for i, distances in enumerate(network): nodeTable.append(Node())
# set distFromSource of startNode to 0 nodeTable[startNode].distFromSource = 0 nodeTable[startNode].visited = True
#write a function to find the neighbour of current node def findNeighbours(currentNode): # find nearest neighbour of currentNode currentRow = network[currentNode] currentNeighbours = [] i = 0
for distance in currentRow: #get back the index number / position if distance = 0 if distance != 0: #save the location currentNeighbours.append(i) i += 1 return currentNeighbours
#print ("\nCurrent Neighbours (of node " + str(currentNode) + "): ") currentNeighbours = findNeighbours(currentNode)
#print (currentNeighbours)
# go through currentNeighbour and see if they have been visited or not # set dustFromSource and previousNode for unvisited
def checkNeighbours():
Besser: explizite Argumente:
def checkNeighbours(currentNeighbours):
for neighbour in currentNeighbours: if nodeTable[neighbour].visited == True: pass #print ("True") else: # calculate their tentative distances from starting node # add distFromSource from currentNode with distance between
currentNode and neighbour # check if less than current newDistance = nodeTable[currentNode].distFromSource + network[currentNode][neighbour]
if (nodeTable[neighbour].distFromSource > newDistance): nodeTable[neighbour].distFromSource = newDistance nodeTable[neighbour].previous = currentNode
checkNeighbours() #printNodeTb()
# go through all distances of unvisited, find lowest and mark as visited def setNewCurrentNode(): global currentNode
Besser:
def setNewCurrentNode(currentNode): ... return currentNode
Aufrufen dann mit:
currentNode = setNewCurrentNode(currentNode)
index = 0 currentDist = sys.maxsize for node in nodeTable: if node.visited == False and node.distFromSource < currentDist: currentNode = index currentDist = node.distFromSource index+=1 nodeTable[currentNode].visited = True print ("\nNew Current Node: " + str(currentNode))
setNewCurrentNode()
Es sollte möglich sein, das Skript so umzuformulieren, dass checkNeighbours() und setNewCurrentNode() nur an einer Stelle aufgerufen werden (hab es nicht ausprobiert).
#total path length tpl = 0
Wenn du statt tpl total_path_length als Namen der Variablen verwendest, ersparst du dir den Kommentar und erhöhst gleichzeitig die Lesbarkeit des Codes.
f = open("09023429spf.txt", "w") f.write(str(chr(startNode+65)))
# check if destination node reached while currentNode != endNode:
#print ("\nCurrent Neighbours (of node " + str(currentNode) + "): ") currentNeighbours = findNeighbours(currentNode) #print (currentNeighbours) checkNeighbours() f.write(str(chr(currentNode+65))) setNewCurrentNode() #add total path length tpl += nodeTable[nodeTable[currentNode].previous].distFromSource
f.write(str(chr(endNode+65)))
str() ist redundant, da chr(...) bereits einen String zurückliefert.
f.write(" " + str(tpl)) f.close()
print ("\nTotal path length: " + str(tpl) + "\n") for node in nodeTable: print (str(node.previous) + " | " + str(node.distFromSource) + " | "
- str(node.visited))
Das wird mit str.format() etwas übersichtlicher, z. B.
print("{} | {} | {}".format(node.previous, node.distFromSource, node.visited))
oder
print("{0.previous} | {0.distFromSource} | {0.visited}".format(node))

Hallo Peter, hallo Christian,
vielen Dank für Eure Mails. Insbesondere die von dir, Peter, hat mir sehr weiter geholfen. Habe versucht das entsprechend Deinen Kommentaren umzustellen. Das mit der total path length war eine blöde Frage von mir. Habe die Info ja schon...schätze ich habe den Überblick verloren. Du hast ja sicher gemerkt das ich noch blutiger Anfänger bin insofern freue ich mich über jegliche weiteren Verbesserungsvorschläge. Ansonsten unten stehend die Lösung für meine Implementierung.
Gibt es einen Grund open(...) as file zu nutzen anstatt des file=open() etc oder ist es einfach nur kürzer?
Gruß Andi _________
import sys
invalid_node = -1
class Node (object): def __init__(self): self.previous = invalid_node self.distFromSource = sys.maxsize self.visited = False
#### FUNCTIONS / METHODS ####
#finds the neighbours of current node def findNeighbours(currentNode): # find nearest neighbour of currentNode currentRow = network[currentNode] currentNeighbours = [] i = 0
for distance in currentRow: #get back the index number / position if distance = 0 if distance != 0: #save the location currentNeighbours.append(i) i += 1 return currentNeighbours
# go through nodetable and add distance and previous if unvisited def calculateTentative(nodeTable,currentNeighbours): for neighbour in currentNeighbours: if nodeTable[neighbour].visited == True: pass else: # calculate tentative distances, add distFromSource newDistance = nodeTable[currentNode].distFromSource + network[currentNode][neighbour]
if (nodeTable[neighbour].distFromSource > newDistance): nodeTable[neighbour].distFromSource = newDistance nodeTable[neighbour].previous = currentNode return nodeTable
# go through all distances of unvisited, find the one with lowest dist def setNewCurrentNode(nodeTable): nextNode = -1 index = 0 nextDist = sys.maxsize
for node in nodeTable: if node.visited == False and node.distFromSource < nextDist: nextNode = index nextDist = node.distFromSource index+=1 return nextNode
def createNetworkTable(): txtfile = open("network.txt", "r") numberOfNodes = 0
network = [] # array containing array of values for each line
# reading file line by line for line in txtfile: # increment nodeCount numberOfNodes += 1
# remove end chars line = line.replace("\n","") line = line.replace("\r","")
# split by comma chars = line.split(",") ints = []
# convert string to int for char in chars: ints.append(int(char))
# append the list of ints to the array network.append(ints) return network
def readRoute(): # read start (dist value = 0) and end node route = open("route.txt", "r")
for line in route: nodes = line.split(">") startNode = nodes[0] endNode = nodes[1]
# get the ascii value and minus 65 startNode =(ord(startNode) - 65) endNode =(ord(endNode) - 65)
return startNode, endNode
def createNodeTable(): # array containing nodeTable visited/unvisited,prevNode and distFromSrc nodeTable = [] i = 0
for i in range(len(network)): nodeTable.append(Node())
# set distFromSource of startNode to 0 nodeTable[startNode].distFromSource = 0 return nodeTable
def calcRoute(nodetable,currentNode,startNode): route = [] total_path_length = 0
while True: route.append(currentNode) if currentNode == startNode: break currentNode = nodeTable[currentNode].previous
route.reverse() route = "".join(chr(node+65) for node in route) return route
#### APPLICATION FLOW ####
#create network table network = createNetworkTable()
#get startNode and endNode from file startNode, endNode = readRoute()
# set currentNode to startNode currentNode = startNode
# create Node table nodeTable = createNodeTable()
f = open("09023429spf.txt", "w")
# continue until desination reached while currentNode != endNode: # get list of current neighbours currentNeighbours = findNeighbours(currentNode) # set current node as visited nodeTable[currentNode].visited = True # get new nodeTable nodeTable = calculateTentative(nodeTable,currentNeighbours) # set new current node currentNode = setNewCurrentNode(nodeTable)
# get the route solution route = calcRoute(nodeTable,currentNode, startNode)
f.write(route) # add the total path length f.write(" " + str(nodeTable[currentNode].distFromSource)) f.close()

Hi Andi.
sackbard schrieb:
Ansonsten unten stehend die Lösung für meine Implementierung.
Nutze doch https://gist.github.com/ für deinen Code. Dann sind deine E-Mails an die Liste kürzer und andere können dir dort auch Verbesserungsvorschläge (als fork) machen.
Viele Grüße
Markus

Hi Markus,
Danke für den Tipp. Code verfügbar unter https://gist.github.com/1866805
Grüße Andi
On 20.02.2012 00:34, Markus Zapke-Gründemann wrote:
Hi Andi.
sackbard schrieb:
Ansonsten unten stehend die Lösung für meine Implementierung.
Nutze doch https://gist.github.com/ für deinen Code. Dann sind deine E-Mails an die Liste kürzer und andere können dir dort auch Verbesserungsvorschläge (als fork) machen.
Viele Grüße
Markus _______________________________________________ python-de maillist - python-de@python.org http://mail.python.org/mailman/listinfo/python-de

sackbard wrote:
Gibt es einen Grund open(...) as file zu nutzen anstatt des file=open() etc oder ist es einfach nur kürzer?
Die Datei wird zu einem definierten Zeitpunkt geschlossen, auch wenn eine Exception auftritt:
f = open("tmp.txt"); 1/0; f.close()
Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: int division or modulo by zero
f.closed
False
with open("tmp.txt") as f:
... 1/0 ... Traceback (most recent call last): File "<stdin>", line 2, in <module> ZeroDivisionError: int division or modulo by zero
f.closed
True
participants (4)
-
Christian Assing
-
Markus Zapke-Gründemann
-
Peter Otten
-
sackbard