Nearest Neighbour - Error code iterable in Python - python

Here is the code I'm using and getting an 'int' object is not iterable error and Idon't know how to fix it.
def shortestpath(graph,start,end,visited=[],distances={},predecessors={}):
"""Find the shortest path between start and end point of a list"""
# detect if it's the first time through, set current distance to zero
if not visited: distances[start]=0
if start==end:
# we've found our end point, now find the path to it, and return
path=[]
while end != None:
path.append(end)
end=predecessors.get(end,None)
return distances[start], path[::-1]
# process neighbors as per algorithm, keep track of predecessors
for neighbor in graph[start]:
if neighbor not in visited:
neighbordist = distances.get(neighbor,sys.maxint)
tentativedist = distances[start] + graph[start][neighbor]
return tentativedist
if tentativedist < neighbordist:
distances[neighbor] = tentativedist
predecessors[neighbor]=start
# neighbors processed, now mark the current point as visited
visited.append(start)
# finds the closest unvisited node to the start
unvisiteds = dict((k, distances.get(k,sys.maxint)) for k in graph if k not
in visited)
closest = min(unvisiteds, key=unvisiteds.get)
# now we can take the closest point and recurse, making it current
return shortestpath(graph,closest,end,visited,distances,predecessors)
#main
graph=[0,8,7,5,2,10]
n=len(graph)
start=graph[0]
end=graph[n-1]
print shortestpath(graph,start,end)

Since you have graph=[0,8,7,5,2,10], graph[start] is an integer therefore you got the error in the for-loop:
for neighbor in graph[start]:
and I don't think you can use graph[start][neighbor] in line: tentativedist = distances[start] + graph[start][neighbor]

Related

Shortest path Graph BFS python

Trying to return the int for shortest path in a graph, using BFS. The idea is to use a q, append into the q as [node,distance] and then when we traverse increase distance and keep track of the count and when we hit our destination first time that means we found shortest path so we return that. But I got error " currNode,distance = q.popleft()
ValueError: not enough values to unpack (expected 2, got 1)"
def shortestPath(graph,nodeA,nodeB):
q = deque((nodeA,0))
visited = set(nodeA)
while q:
currNode,distance = q.popleft()
if currNode == nodeB:
return distance
for neighbor in graph[currNode]:
if neighbor not in visited:
visited.add(neighbor)
q.append([neighbor,distance+1])
return -1
graph_three = {
'w':['x','v'],
'x':['w','y'],
'y':['x','z'],
'z':['y','v'],
'v':['z','w']
}
print(shortestPath(graph_three,'w','z'))
Deque takes an iterable of elements as input, you gave it a tuple so your deque will contains two elements instead of the expected one tuple of two elements.
fix line 2 into:
q = deque([(nodeA,0)])
also here is a cleaner implementation of BFS:
def shortestPath(graph, root, target):
if root == target: return 0
q = collections.deque(root)
visited = set(root)
distance = 0
while q:
for _ in range(len(q)):
node = q.popleft()
for neighbor in graph[node]:
if neighbor == target:
return distance + 1
elif neighbor not in visited:
visited.add(neighbor)
q.append(neighbor)
distance += 1
return -1

Set list next to None

When I try to make the next attribute of a node, p, of a linked list point to None, I use p.next = None. But what if I want to make the node corresponding to p.next to None?
An example would be when try to rotate a linked list, which ends with a node's next equal to None, I want to make the new list's last element's next point to None but I think I keep deleting the element that it pointed to.
Here's my code for rotating the list by k positions. If you want to see the full description of the problem see here
def rotate(head, k):
'''
head is pointer to the head, k is the number of positions to rotate
'''
if not head or k == 0:
return head
p = head
d = head
counter = 1
while p.next != None:
counter += 1
p = p.next
out = ListNode(0)
if k % counter == 0:
return head
if counter < k:
counter = counter % k
for _ in range(counter):
p.next = d
d = d.next
p = p.next
out = p
d.next.next = None
return out
Sounds like you want to take the last k values and append them to the front.
p.next is the next node. In general when we want to change p's next we need to grab temp = p.next p.next = newNode and then we can continue.
In this case though, I'd find the length of the list, set tail.next = head, subtract k (accounting for wraparound), then walk forward till N-k, and set that node's p.next = None
Something like:
p, len, prev = head, 0, None
while p:
prev = p
p = p.next
len += 1
# prev is tail, set it's next to head
prev.next = head
# find the node to detach
p = head
for i in xrange(len):
p = p.next
p.next = None
You'll need to figure out corner cases

How to search through tree to find the maximum sum of a set of nodes' value

G
B
H
A D
E
C I
F
1 2 3 (level)
Suppose there is a Tree in the above structure.
Each node is linked with the nodes of their parent and children. Also each node is linked with one node previously added and somewhat related to the current node.
Suppose now that each node has five properties:
the name of the node (e.g. 'A', 'B', 'C', etc)
the node of their parent (e.g. if node.name == 'B', then node.parent.name == 'A' is True)
the node beneath them (e.g. if node.name == 'G', then node.previous.name == 'H' is True, However if node.name == 'H', then node.previous.name == 'B' is True)
list of children nodes (e.g. if node.name == 'A', then [c.name for c in node.children] == ['B', 'D', 'C'] is True)
node.value (e.g. isinstance(node.value, int) is True)
Now if I want to search through the Tree to find the maximum value of a group of related nodes with the given number n which denotes the group size.
(e.g. node E relates to node I and node C, but node F, however, node I doesn't relate to node E, but does relate to node F and node C)
How exactly can I design this function
Here is my understanding of your problem: You want to enumerate all groups of related nodes of size n, and find the maximum sum of the values of the nodes in such a group.
Here is an algorithm:
For each node keep a sorted list of its children, sorted with respect to the values of the children. Iterate over all the nodes. For each node,
compute the maximum of the following four numbers:
current node + largest n-1 children
current node + largest n-2 children + parent
current node + largest n-2 children + previous
current node + largest n-3 children + parent + previous
Remember to take care of special cases, e.g., if a node has few children, parent=previous etc.
(actually you might just put all related nodes of a node in one sorted list and pick the n-1 largest).
Since a node apparently can be related to its childrens children, the above will not work.
I have given it another go:
For each node keep a list l, whose index is the maximum value obtained using the node + up to i-1 children.
For each leaf node this is simply going to be [0, leaf.value, ...].
For each node, assume that is has one child. Then node.l is easy to compute, it is simply:
node.l[i] = child.l[i-1] + node.value
If we then add another child to this node, we may use 0 through n-1 nodes from the child, depeneding on what is optimal. This is computed using (kind of, see the code below)
node.l[i] = max(node.l[i], node.l[i-k] + child.l[i])
This is implemented below.
It is easy to accomodate for the extra connectedness due to node.previous. We just make an extra pass through the list of nodes at the end, when all node.l's are computed.
for node in nodes:
# l[i] = maximum value obatined using node + up to i-1 children
node.l = [0 for i in xrange(n+1)]
node.visited = False
Q = [] # Queue
for leaf in nodes:
if len(leaf.children) > 0: continue
Q.append(leaf)
leaf.visited = True
while Q:
t = Q.pop(0)
l = [0]
for i in xrange(1, n+1):
l.append(t[i-1] + t.value)
t.l = l
if not t.parent: break
for l in xrange(0, n+1):
for i in xrange(l, n+1):
t.parent.l[i] = max(t.parent[i], t.parent[i-l] + t[l])
if not t.parent.visited:
t.parent.visited = True
Q.append(t.parent)
m = 0
for node in nodes:
m = max(m, node[n], node[n-1] \
+ (node.previous.value if node.previous else 0))
print m
The running time is n*n*(number of nodes).

Python TSP Held-Karp algorithm

I'm trying to implement Held-Karp in Python but it doesn't seem to be working. There are two differences in my problem from the classical TSP problem (as used in the description of the H-K algorithm I found in the web):
- I don't need to return to the original node. I think this is called a Hamiltonian cycle but I'm not very familiar with graph algorithms so I'm not entirely sure. Each city needs to be visited once as in TSP
- Some edges in the graph are missing
I used networkx and created this function:
def hk(nodes,Graph,start_node, total_ops, min_weight = 9999999,min_result = []):
nodes.remove(start_node)
# removes the current node from the set of nodes
for next_node in nodes:
total_ops += 1
current_weight = 0
try:
current_weight += Graph[start_node][next_node]["weight"]
# checks if there's an edge between the current node and the next node
# If there's an edge, adds the edge weight
except:
continue
sub_result = []
if len(nodes) > 1:
new_nodes = set(nodes)
sub_result,sub_weight,total_ops = hk(new_nodes,Graph,next_node, total_ops)
#calculates the minimum weight of the remaining tree
current_weight += sub_weight
if current_weight < min_weight:
# if the weight of the tree is below the minimum weight, update minimum weight
min_weight = current_weight
min_result = [next_node] + sub_result
return min_result,min_weight,total_ops
But something is clearly wrong as I'm expecting O(n ** 2 * 2 ** n) complexity but am getting O(n!) instead, same as for the brute force method (trying all combinations one by one). Clearly, there's an error in my implementation.
Thank you.

How can I restrict a KDTree query to a subset of the nodes?

tl;dr
I need a way to find "Foreign Nearest Neighbors" using a KDTree or some other spatial data structure. i.e find the nearest neighbor in a subset of the tree.
I built a MST algorithm that uses a KDTree to find nearest neighbors. However eventually it needs to look beyond nearest neighbors and into "Nearest Foreign Neighbors" as to connect distant nodes. My first approach simply iteratively increases k-nn parameter until the query returns a node in the subset. I cache k as each time the function is called the breadth of its search is expanded and there is no point in searching the previous k < k_cache.
def FNNd(kdtree, A, b):
"""
kdtree -> nodes in subnet -> coord of b -> index of a
returns nearest foreign neighbor a∈A of b
"""
a = None
b = cartesian_projection(b)
k = k_cache[str(b)] if str(b) in k_cache else 2
while a not in A:
#scipy kdtree where query -> [dist], [idx]
_, nn = kdtree.query(b, k=k)
a = nn[-1][k-1]
k += 1
k_cache[str(b)] = k-1
#return NN a ∈ A of b
return a
However this is quite 'hacky' and inefficient, so I was thinking I could implement a KDTree myself that stops traversing when doing so would result in subtrees that doesn't include the restricted subset. Then the nearest neighbor in the subset would have to be that left or right branch. After many attempts I can't seem to get this to actually work. Is there a flaw in my logic? A better way to do this? A better Data Structure?
Heres my KDTree
class KDTree(object):
def __init__(self, data, depth=0, make_idx=True):
self.n, self.k = data.shape
if make_idx:
# index the data
data = np.column_stack((data, np.arange(self.n)))
else:
# subtract the indexed dimension in later calls
self.k -= 1
self.build(data, depth)
def build(self, data, depth):
if data.size > 0:
# get the axis to pivot on
self.axis = depth % self.k
# sort the data
s_data = data[np.argsort(data[:, self.axis])]
# find the pivot point
point = s_data[len(s_data) // 2]
# point coord
self.point = point[:-1]
# point index
self.idx = int(point[-1])
# all nodes below this node
self.children = s_data[np.all(s_data[:, :-1] != self.point, axis=1)]
# branches
self.left = KDTree(s_data[: len(s_data) // 2], depth+1, False)
self.right = KDTree(s_data[len(s_data) // 2 + 1: ], depth+1, False)
else:
# empty node
self.axis=0
self.point = self.idx = self.left = self.right = None
self.children = np.array([])
def query(self, point, best=None):
if self.point is None:
return best
if best is None:
best = (self.idx, self.point)
# check if current node is closer than best
if distance(self.point, point) < distance(best[1], point):
best = (self.idx, self.point)
# continue traversing the tree
best = self.near_tree(point).query(point, best)
# traverse the away branch if the orthogonal distance is less than best
if self.orthongonal_dist(point) < distance(best[1], point):
best = self.away_tree(point).query(point, best)
return best
def orthongonal_dist(self, point):
orth_point = np.copy(point)
orth_point[self.axis] = self.point[self.axis]
return distance(point, self.point)
def near_tree(self, point):
if point[self.axis] < self.point[self.axis]:
return self.left
return self.right
def away_tree(self, point):
if self.near_tree(point) == self.left:
return self.right
return self.left
[EDIT] Updated attempt, however this doesn't guarantee a return
def query_subset(self, point, subset, best=None):
# if point in subset, update best
if self.idx in subset:
# if closer than current best, or best is none update
if best is None or distance(self.point, point) < distance(best[1], point):
best = (self.idx, self.point)
# Dead end backtrack up the tree
if self.point is None:
return best
near = self.near_tree(point)
far = self.away_tree(point)
# what nodes are in the near branch
if near.children.size > 1:
near_set = set(np.append(near.children[:, -1], near.idx))
else: near_set = {near.idx}
# check the near branch, if its nodes intersect with the queried subset
# otherwise move to the away branch
if any(x in near_set for x in subset):
best = near.query_subset(point, subset, best)
else:
best = far.query_subset(point, subset, best)
# validate best, by ensuring closer point doesn't exist just beyond partition
if best is not None:
if self.orthongonal_dist(point) < distance(best[1], point):
best = far.query_subset(point, subset, best)
return best

Categories