Python: Dijkstra' algorithm - python

need a help with Dijkstra. I found a lot of codes on the internet, but I can't use any of them, because I'm not given a graph, but just lists of Vertexes & Edges into createGraph function. It's a homework and I gotta have some attributes in classes.
This is what I have:
class Vertex:
def __init__(self, id, name):
self.id = id
self.name = name
self.minDistance = float('inf')
self.previousVertex = None
self.edges = []
self.visited = False
class Edge:
def __init__(self, source, target, weight):
self.source = source
self.target = target
self.weight = weight
class Dijkstra:
def __init__(self):
self.vertexes = []
self.result = 0
def createGraph(self, vertexes, edgesToVertexes):
for i in range(len(vertexes)):
self.vertexes.append(vertexes[i])
for j in range(len(edgesToVertexes)):
if edgesToVertexes[j].source == vertexes[i].id:
vertexes[i].edges.append(edgesToVertexes[j])
def getVertexes(self):
return self.vertexes
def findMinID(self):
maxDistance = 1000000
curVertex = None
result = None
for i in range(len(self.vertexes)):
self.vertexes[i] = curVertex
if curVertex.visited is False and curVertex.minDistance < maxDistance:
curVertex = result
curVertex.minDistance = maxDistance
else:
pass
self.result = result
return
def computePath(self, sourceId):
start = None
end = None
road = None
while start is None:
if Vertex.id == sourceId:
start = Vertex
start.minDistance = 0
start.visited = True
for i in range(len(start.edges)):
start.edges[i].target = end
start.edges[i].weight = road
if road < end.minDistance:
end.minDistance = start.minDistance + road
end.previousVertex = start.id
else:
pass
self.findMinID()
self.computePath(self.result.id)
I'm still beginner so I tried to keep it simple, but it's not working as it raises error:
'type' object is not subscriptable
or:
AttributeError: type object 'Vertex' has no attribute 'id'
which makes absolutely no sense to me why.
I can use any help, thanks in advance!

When you put the line:
self.vertexes = Vertex
you are assigning the variable to the actual class. Probably what you wanted to do was make an empty list, as you append to it later:
self.vertexes = []
I would assume this is where the error comes from, as if you ever try to iterate over self.vertexes, you are iterating over the Vertex class, which is impossible and throws that error.
You also have later:
start = Vertex
Try initializing the start, like:
start = Vertex(sourceId, "vertex")
Also, the line before that you have
if Vertex.id == sourceId:
meaning that you might want to make the id variable in Vertex static:
class Vertex:
id = 0
def __init__(self, id, name):
self.id = id
id += 1
Some suggestions: class tutorial in python
Edit:
To find the vertex that has the id you want, use a filter:
start = None
for v in self.vertexes:
if v.id == sourceId:
start = Vertex(sourceId, v.name)
start.minDistance = 0
break

Related

Unable to figure out which data structure to use for efficiency

I come from C background currently learning Python. My task is to create a general tree. The input to the program is in two passes. In the first pass I must collect the identity, name, role and dept of a person. In the second pass I get to know the parent of a node, the manager. So I must store the values transiently. In C I would typically use an array of structs or a linked list depending on the availability of the size information. But I am lost here in Python, not even sure if what I am doing is okay let alone efficient.
Thanks in advance,
Preeti.
if __name__ == "__main__":
# Have successfully created the tree and added nodes by hardcoding values as shown below in commented code
# create_tree = Tree()
# Tree.add_node(42, "Stephen", "Time Cone Radiation", "Black Hole")
# But unable to figure out how to store transient info and use it later to create the tree.
num = 8
list = []
backup_num = num
while num:
id, name, role, dept = raw_input().split()
num -= 1
list.append((id, name, role, dept))
while backup_num:
id, parent = raw_input().split()
backup_num -= 1
#For an id in the list above locate it, and call add_node.
# But not sure how and what is an efficient way.
This will give you a fare idea. Hope this helps.
class Tree():
def __init__(self):
self.length = 0
self.data = {}
def add_node(self, nodeid, name, role, dept):
obj = {}
obj["child"] = {"left": None, "right": None}
obj["parent_id"] = None
obj["name"] = name
obj["role"] = role
obj["dept"] = dept
self.data[nodeid] = obj
self.length += 1
return True
# which_one : Left or Right
def update_child_id(self, which_one, nodeid_parent, nodeid_child):
self.data[nodeid_parent]["child"][which_one] = nodeid_child
return True
def update_parent(self, nodeid, parent_id):
self.data[nodeid]["parent_id"] = parent_id
return True
def display_node(self, nodeid):
obj = self.data[nodeid]
print("Node:", nodeid)
print("Parent:", obj["parent_id"], ", Name:", obj["name"], ", Role: ", obj["role"], ", Dept: ", obj["dept"])
def display_child(self, nodeid):
print(self.data[nodeid]["child"].items())
# Main
test = Tree()
# Get the identity and then add here
node_id, name, role, dept = [42, "Stephen", "Time Cone Radiation", "Black Hole"]
test.add_node(node_id, name, role, dept)
# Get the parent id and add here
parent_id, parent = [6, "James"]
test.update_parent(node_id, parent_id)
test.display_node(42)
test.display_child(42)

Classes in Linked List not working

Got a schoolwork to do showroom with 2 classes: Car & Node, while Node data contain Car class with its data. Then I have to make a Linked list, should be doubly, but I think a simple should work as well, with Nodes containing Cars. The only function in Linked list is inserting a new Node with new Car. It should be sorted by price of cars upwardly.
Tried this, but it keeps telling me
TypeError: '<' not supported between instances of 'NoneType' and 'NoneType'
class Car:
def __init__(self, id = None, name = None, brand = None, price = None, active = None):
self.id = id
self.name = name
self.brand = brand
self.price = price
self.active = active
class Node:
def __init__(self, data):
self.next = None
self.data = Car()
class LinkedList:
def __init__(self):
self.head = Node(None)
def insertNode(self, car):
newNode = Node(car)
curNode = self.head
if self.head.data is None:
self.head = newNode
if newNode.data.price < curNode.data.price:
newNode.next = curNode
self.head = newNode
else:
while curNode.next is not None and curNode.next.data.price <= newNode.data.price:
curNode = curNode.next
newNode.next = curNode.next
curNode.next = newNode
db = LinkedList()
def init(cars):
for car in cars:
db.insertNode(car)
def add(car):
db.insertNode(car)
Did I miss something, 'cause I think it should be working.
In Node.__init__ you have the line self.data = Car() which creates a Car instance using the default values (which are all None). That means that the price of every Car in the list is None. Later, you are getting an exception when you try comparing prices with newNode.data.price < curNode.data.price because you can't compare None values.
You probably need to replace self.data = Car() with something else. It's not obvious to me from your current code where the car data is supposed to come from or what format it is in. If the cars sequence you're iterating over in the top level init function is a list of Car instances already, then you should probably just do self.data = data in Node.__init__. Otherwise you'll need to do something else to extract the car data and pass it to the Car constructor. You may also want to consider getting rid of the default arguments to Car.__init__, since it doesn't seem to make much sense to create a car without them.
I see several problems, mainly regarding type consistency, in your code. You should maybe rethink what exactly the class structure here is supposed to do, how to set the default values etc. Also: Do you want to have the nodes next variable to be another node?
Assuming the following: We have Cars. Each Car has a Name, Brand and pricetag. We want two cars to be connected by a Node. And we want lists that can hold nodes and allow us to insert a new Node. Insertion should happen such that the node hierarchy connects cars in ascending price value. Two neighboring nodes share one car. You could write this as something like:
class Car:
def __init__(self, name = " ", brand = " ", price = 0):
self.name = name
self.brand = brand
self.price = price
class Node:
def __init__(self,car1,car2):
assert type(car1) == type(car2) == Car
if car1.price > car2.price:
self.next = car1
self.current = car2
else:
self.next = car2
self.current = car1
class LinkedList:
def __init__(self,firstnode):
self.ListOfNodes = [firstnode]
def insertNode(self, car):
for i in range(0,len(self.ListOfNodes)):
curnod = self.ListOfNodes[i]
newnod = Node(car,car)
if car.price < curnod.current.price:
if i<len(self.ListOfNodes): #If its not the last node
newnod.next = curnod.current
if i>0: #If its not the first node, i.e. it has a predecessor
ListOfNodes[i-1].next = newnod.current
self.ListOfNodes.insert(i,newnod)
return
elif car.price < curnod.next.price:
newnod.current = curnod.current
curnod.current = car
self.ListOfNodes.insert(i,newnod)
return
newnod.current = self.ListOfNodes[-1].next #this is only reached if the price is higher than all before
self.ListOfNodes.append(newnod)
car1 = Car(name = "baby",brand= "honda", price = 1000)
car2 = Car(name = "yomomma",brand= "Benz", price = 10)
car3 = Car(name = "PussyWagon",brand= "Dodge", price = 100)
car4 = Car(name = "FakeTaxi",brand= "HellNah", price = 10000000)
car5 = Car(name = "LondonTaxi",brand= "ChumBucket", price = 1)
p = Node(car2,car1)
lst = LinkedList(p)
lst.insertNode(car3)
lst.insertNode(car4)
lst.insertNode(car5)
It's very generic but it should work.

Print dict with custom class as values wont call their string method?

I was messing around with classes in python and wrote 2 little ones:
class ClaElement:
start = None
end = None
basesLeft = None
orientation = None
contig = None
size = None
def __init__(self, contig, start, end, orientation, basesLeft=None):
self.contig = contig
self.start = start
self.end = end
self.orientation = orientation
self.basesLeft = basesLeft
self.size = self.end - self.start
def __str__(self):
return "{ClaElement: "+str(self.contig)+"_"+str(self.start)+"_"+str(self.end)+"_"+str(self.orientation)+"}"
def getSize(self):
return self.size
class ClaCluster:
contig = None
clusterElements = []
def __init__(self, contig, firstElement):
self.contig = contig
self.addElement(firstElement)
def addElement(self, claElement):
self.clusterElements.append(claElement)
def getFirst(self):
return self.clusterElements[0]
def getLast(self):
return self.clusterElements[-1]
def getElements(self):
return self.clusterElements
def getContig(self):
return self.contig
def __str__(self):
return "{ClaCluster: "+str(self.contig)+" "+str(len(self.clusterElements))+" elements}"
And my test-main:
from ClaElement import ClaElement
from ClaCluster import ClaCluster
if __name__ == '__main__':
ele = ClaElement("x",1,2,"left")
claDict = dict()
cluster = ClaCluster("x", ele)
claDict["hello"] = cluster
print(claDict)
print(claDict["hello"])
print(ele)
This leads to the following output:
{'hello': <ClaCluster.ClaCluster object at 0x7fe8ee04c5f8>}
{ClaCluster: x 1 elements}
{ClaElement: x_1_2_left}
Now my question is why is the output of my first print the memory address even though I provided a functioning string-method for my class ClaCluster? Is there a way to get the method invoked when I am printing the dictionary or do I have to iterate by hand?
The __str__() method of the built-in dict type uses the __repr__() method of your class, not __str__(). Simply rename your method, and all should work fine.

I cannot understand a case of passing an object as a parameter

I have a class Node with a function defined
class Node(object):
def __init__(self, index, state = None, input = None, directed_neighbours=False):
"""
Parameters
----------
index : int
Node index. Must be unique in the graph.
"""
self._input = input
self.state = state
#self._status = 'active'
self._index = int(index)
self._neighbours = set()
self._port_count = 0
self._ports = []
if directed_neighbours:
self._predecessors = set()
self._successors = self._neighbours
self._directed_neighbours = True
else:
self._successors = self._neighbours
self._predecessors = self._neighbours
self._directed_neighbours = False
#property
def setStatus(self, status):
self._status = status
I have another function
def init(node):
node.setStatus('active')
Now, I have a class
class DistAlgo:
def __init__(self, name, initFunc, states, messages, sendFunc, receiveFunc, stoppingCheck):
self.name = name
#self.inputGraph = inputGraph
self.initFunc = initFunc
self.states = states
self.messages = messages
self.sendFunc = sendFunc
self.receiveFunc = receiveFunc
self.comm_round = 0
self.stoppingCheck = stoppingCheck
def run(self, inputGraph):
for node in inputGraph.nodes:
print('hello', node)
node.state = self.initFunc(node)
<....more code...>
When I create an object of DistAlgo
myalgo = DistAlgo('BMM', init, states, messages, send, receive, stoppingCheck)
and then call its run function:
myalgo.run(problemGraph)
I get an error in the init function above, as:
TypeError: setStatus() missing 1 required positional argument: 'status'
I surely am doing more than one thing wrong I guess, as this is my first Python try. Please point them out!
Properties work a bit differently:
#property
def status(self):
return self._status
#status.setter
def status(self, status):
self._status = status
Now you can set the value with an assignment:
node.status = 'active'

Python priorityQueue.get() returns int instead of object

I am currently developing an AI system in python to solve the bloxorz game using the A* search algorithm.
Naturally, the algorithm stores the nodes in a priority queue,but when i try to get() an element from the queue, it returns an int instead of the object. As I am very new to python, I would appreciate it if someone can clarify.
My A* algorithm:
class Astar:
def __init__(self, start):
self.path = []
self.visitedQueue = []
"""hold visited in a queue to avoid duplicates"""
self.priorityQueue = PriorityQueue()
self.start = start
def Solve(self):
"""the a* algorithm"""
StartNode = Node_Map(self.start, 0, self.start)
count = 0
self.priorityQueue.put(0, count, StartNode)
while not self.path and self.priorityQueue.qsize():
closestChild = self.priorityQueue.get()[2]
closestChild.createChildren()
self.visitedQueue.append(closestChild.matrix)
for child in closestChild.children:
if child.matrix not in self.visitedQueue:
count += 1
if child.getH == 0:
self.path = child.path
break
self.priorityQueue.put(child.getH+count, count, child)
""" put in priority queue according to f(n)=h(n)+g(n)"""
if not self.path:
print("goal not possible")
return self.path
My Node class and Node_Map class:
class Node(object):
def __init__(self, matrix, parent, start=0):
self.children = []
self.matrix = {}
self.parent = parent
self.xPos = 0
self.yPos = 0
self.goalX = 0
self.goalY = 0
if parent:
self.path = parent.path[:]
self.start = parent.start
self.path.append = [matrix]
else:
self.path = [matrix]
self.start = start
def getDist(self):
""" abstract function to get our estimated distance to the goal"""
pass
def createChildren(self):
"""absract to create children from successor actions"""
pass
class Node_Map(Node):
def __init__(self, matrix, parent, start=0):
super(Node_Map, self).__init__(matrix, parent, start)
self.h = self.getH()
priorityQueue.put(child.getH+count, count, child)
The above line calls put with the arguments: item=child.getH+count, block=count, and timeout=child. As a result, only child.getH+count is be considered as the 'item' that get will retrieve. Try putting all three objects into a tuple:
priorityQueue.put((child.getH+count, count, child))
This way, item will be the tuple (child.getH+count, count, child), and the other two arguments, block, and timeout, will stay as their default values (True and None, respectively).

Categories

Resources