AttributeError: Node instance has no attribute '__getitem__' - python

First I want to say that I searched for my problem but due to the nature of the problem + the code I have to work with I did not find a solution. Therefore here is my problem:
Traceback (most recent call last):
File "AlienTilesMain.py", line 28, in <module>
goal = astar_search(prob, prob.h1)
File "/home/chris/Desktop/search.py", line 274, in astar_search
return best_first_graph_search(problem, lambda n: n.path_cost + h(n))
File "/home/chris/Desktop/search.py", line 213, in best_first_graph_search
frontier.append(node)
File "/home/chris/Desktop/utils.py", line 738, in append
bisect.insort(self.A, (self.f(item), item))
File "/home/chris/Desktop/utils.py", line 612, in memoized_fn
val = fn(obj, *args)
File "/home/chris/Desktop/search.py", line 274, in <lambda>
return best_first_graph_search(problem, lambda n: n.path_cost + h(n))
File "/home/chris/Desktop/utils.py", line 612, in memoized_fn
val = fn(obj, *args)
File "/home/chris/Desktop/AlienTiles.py", line 57, in h1
n = len(state[0])
AttributeError: Node instance has no attribute '__getitem__'
and my code is this one:
def h1(self, state):
n = len(state[0])
.
.
return value
in my main file:
goal = astar_search(prob, prob.h1)
and here are the Problem, Node Class and A* :
class Problem(object):
def __init__(self, initial, goal):
"""The constructor specifies the initial state, and possibly a goal
state, if there is a unique goal. Your subclass's constructor can add
other arguments."""
self.initial = initial; self.goal = goal
def actions(self, state):
"""Return the actions that can be executed in the given
state. The result would typically be a list, but if there are
many actions, consider yielding them one at a time in an
iterator, rather than building them all at once."""
abstract
def result(self, state, action):
"""Return the state that results from executing the given
action in the given state. The action must be one of
self.actions(state)."""
abstract
class Node:
"""A node in a search tree. Contains a pointer to the parent (the node
that this is a successor of) and to the actual state for this node. Note
that if a state is arrived at by two paths, then there are two nodes with
the same state. Also includes the action that got us to this state, and
the total path_cost (also known as g) to reach the node. Other functions
may add an f and h value; see best_first_graph_search and astar_search for
an explanation of how the f and h values are handled. You will not need to
subclass this class."""
def __init__(self, state, parent=None, action=None, path_cost=0):
"Create a search tree Node, derived from a parent by an action."
update(self, state=state, parent=parent, action=action,
path_cost=path_cost, depth=0)
if parent:
self.depth = parent.depth + 1
def __repr__(self):
return "<Node %s>" % (self.state,)
def expand(self, problem):
"List the nodes reachable in one step from this node."
return [self.child_node(problem, action)
for action in problem.actions(self.state)]
def child_node(self, problem, action):
"Fig. 3.10"
next = problem.result(self.state, action)
return Node(next, self, action,
problem.path_cost(self.path_cost, self.state, action, next))
def solution(self):
"Return the sequence of actions to go from the root to this node."
return [node.action for node in self.path()[1:]]
def path(self):
"Return a list of nodes forming the path from the root to this node."
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def astar_search(problem, h=None):
"""A* search is best-first graph search with f(n) = g(n)+h(n).
You need to specify the h function when you call astar_search, or
else in your Problem subclass."""
h = memoize(h or problem.h, 'h')
return best_first_graph_search(problem, lambda n: n.path_cost + h(n))

Related

Practicality of the position attribute of a Positional List Implementation in Python?

I am reading Chapter 7 of Data Structures and Algorithms in Python and I am finding the Positional List ADT quite hard to understand, the implementation given by the book looks like this:
class _DoublyLinkedBase:
""" A base class providing a doubly linked list representation."""
class _Node:
__slots__ = '_element' , '_prev' , '_next' # streamline memory
def __init__(self, element, prev, next): # initialize node’s fields
self._element = element # user’s element
self._prev = prev # previous node reference
self._next = next # next node reference
# MAIN METHODS
def __init__(self):
self._header = self._Node(None, None, None)
self._trailer = self._Node(None, None, None)
self._header._next = self._trailer # trailer is after header
self._trailer._prev = self._header # header is before trailer
self._size = 0 # number of elements
def __len__(self):
return self._size
def is_empty(self):
return self._size == 0
def _insert_between(self, e, predecessor, successor):
newest = self._Node(e, predecessor, successor) # linked to neighbors
predecessor._next = newest
successor._prev = newest
self._size += 1
return newest
def _delete_node(self, node):
predecessor = node._prev
successor = node._next
predecessor._next = successor
successor._prev = predecessor
self._size -= 1
element = node._element # record deleted element
node._prev = node._next = node._element = None # deprecate node
return element # return deleted element
class PositionalList(_DoublyLinkedBase):
""" A sequential container of elements allowing positional access."""
#-------------------------- nested Position class --------------------------
class Position:
""" An abstraction representing the location of a single element."""
def __init__(self, container, node):
""" Constructor should not be invoked by user."""
self._container = container
self._node = node
def element(self):
""" Return the element stored at this Position."""
return self._node._element
def __eq__(self, other):
""" Return True if other is a Position representing the same location."""
return type(other) is type(self) and other._node is self._node
def __ne__(self, other):
""" Return True if other does not represent the same location."""
return not (self == other) # opposite of eq
#-------------------------- End of nested Position class --------------------
#------------------------------- utility method -------------------------------
def _validate(self, p):
""" Return position s node, or raise appropriate error if invalid."""
if not isinstance(p, self.Position):
raise TypeError("p must be proper Position type")
if p._container is not self:
raise ValueError("p does not belong to this container")
if p._node._next is None: # convention for deprecated nodes
raise ValueError("p is no longer valid")
return p._node
#------------------------------- utility method -------------------------------
def _make_position(self, node):
""" Return Position instance for given node (or None if sentinel)."""
if node is self._header or node is self._trailer:
return None # boundary violation
else:
return self.Position(self, node) # legitimate position
#------------------------------- accessors -------------------------------
def first(self):
""" Return the first Position in the list (or None if list is empty)."""
return self._make_position(self._header._next)
def last(self):
""" Return the last Position in the list (or None if list is empty)."""
return self._make_position(self._trailer._prev)
def before(self, p):
""" Return the Position just before Position p (or None if p is first)."""
node = self._validate(p)
return self._make_position(node._prev)
def after(self, p):
""" Return the Position just after Position p (or None if p is last)."""
node = self._validate(p)
return self._make_position(node._next)
def __iter__(self):
""" Generate a forward iteration of the elements of the list."""
cursor = self.first( )
while cursor is not None:
yield cursor.element( )
cursor = self.after(cursor)
#------------------------------- mutators -------------------------------
# override inherited version to return Position, rather than Node
def _insert_between(self, e, predecessor, successor):
""" Add element between existing nodes and return new Position."""
node = super()._insert_between(e, predecessor, successor)
return self._make_position(node)
def add_first(self, e):
"""" Insert element e at the front of the list and return new Position."""
return self._insert_between(e, self._header, self._header._next)
def add_last(self, e):
""" Insert element e at the back of the list and return new Position."""
return self._insert_between(e, self._trailer._prev, self._trailer)
def add_before(self, p, e):
""" Insert element e into list before Position p and return new Position."""
original = self._validate(p)
return self._insert_between(e, original._prev, original)
def add_after(self, p, e):
""" Insert element e into list after Position p and return new Position."""
original = self._validate(p)
return self._insert_between(e, original, original._next)
def delete(self, p):
""" Remove and return the element at Position p."""
original = self._validate(p)
return self._delete_node(original) # inherited method returns element
def find(self, e):
if len(self) == 0:
raise ValueError('The list is empty')
position = self.first()
while position is not None:
element = position.element()
if element == e:
return position
position = self.after(position)
My question is about the position attribute. We can see that in the constructor of the Position class, there is a container attribute that never gets used explicitly, and this confuses me. I was thinking that maybe a position is something like an index that the user can use to access a certain node.
For instance, when I use the method find(e) to find an element e in the positional list, the method returns the position of the said element, and this position looks something like this:
<main.PositionalList.Position object at 0x7f43acade7f0>.
So I wonder what is the utility of the position if it is just an object and not an integer or string understandable by the user?
there is a container attribute that never gets used explicitly, and this confuses me
Actually, it is used: in the _validate method, which itself is used in several other methods.
Its purpose is to verify that a node -- that is passed to a container's before, after, add_before, add_after, or delete method -- is a node that already belongs to that container, without having to actually find it in the container, which would be a slow process.

Python Set not Detecting Duplicate Node

I have created a Graph class along with a Node class that I've tested. It is working with basic tests. I'm now trying to test with a custom input file and I'm running into an error where some of the Nodes are being duplicated. In the Graph class, there is a set called Nodes where the Node being created is added. However, in my parser file I have a checker which checks to see if the Node with the value has been added before but it's not working properly.
Even after adding in the hash function below, I still get set([Alpha, Beta, Hotel, Alpha]).
What am I doing wrong?
Test File:
directed unweighted
Alpha=Hotel
Alpha=Beta
Beta=Charlie
Charlie=Juliett
Charlie=Juliett
Delta=Foxtrot
Delta=Golf
Echo=Charlie
Echo=Delta
Foxtrot=Golf
Golf=Juliett
Golf=Alpha
Hotel=Echo
Hotel=India
India=Beta
India=Golf
Juliett=Golf
Graph and Node Class:
class Graph:
def __init__(self):
self.Nodes = set()
def addVertex(self, vertex):
self.Nodes.add(vertex)
def getVertices(self):
return self.Nodes
#staticmethod
def addEdgeDirect(fromEdge, toEdge, cost=1):
fromEdge.neighbors[toEdge] = cost
class Node():
def __init__(self, val = None):
self.value = val
self.neighbors = {}
def getEdges(self):
return self.neighbors.keys()
def __repr__(self):
return str(self.value)
Test File Parser:
from graph import Graph, Node
graph = Graph()
file1 = open('Graphs/du.gl', 'r')
Lines = file1.readlines()
direction = Lines[0].split(" ")[0].strip()
weight = Lines[0].split(" ")[1].strip()
count = 0
if(direction == "directed"):
if(weight == "unweighted"):
for line in Lines:
count += 1
if(count == 1):
continue
node1 = Node(line.split("=")[0].strip())
node2 = Node(line.split("=")[1].strip())
if node1 not in graph.Nodes:
print("not found, to be added")
graph.addVertex(Node(node1))
if node2 not in graph.Nodes:
graph.addVertex(Node(node2))
print(graph.getVertices())
graph.addEdgeDirect(node1,node2)
# print("Line{}: {}".format(count, line.strip()))
In a set objects are always distinguished by their object ID (reference). So it doesn't help to define __hash__ either.
I would suggest to:
Use a dictionary instead of a set
Only create Node instances when you already know that you need a new instance -- so after having checked that the Nodes dictionary doesn't have it yet
By consequence: pass the string value to addVertex instead of a Node instance.
With some other little changes, your code could be:
class Graph:
def __init__(self):
self.nodes = {}
def addVertex(self, key):
if key not in self.nodes:
self.nodes[key] = Node(key)
return self.nodes[key]
def getVertices(self):
return self.nodes.values()
#staticmethod
def addEdgeDirect(fromEdge, toEdge, cost=1):
fromEdge.neighbors[toEdge] = cost
class Node():
def __init__(self, val=None):
self.value = val
self.neighbors = {}
def getEdges(self):
return self.neighbors.keys()
def __repr__(self):
return str(self.value)
graph = Graph()
file1 = open('du.gl', 'r')
firstline, *lines = file1.readlines()
direction, weight = firstline.split()
if direction == "directed":
if weight == "unweighted":
for line in lines:
graph.addEdgeDirect(*(graph.addVertex(key.strip())
for key in line.split("=")))
print(graph.getVertices())
Addendum
In comments you ask about getEdges and how it could return more information.
Here is a variant of that method:
def getEdges(self):
return { self: self.neighbors }
If you then do this:
print(graph.nodes['Alpha'].getEdges())
...it will output:
{Alpha: {Hotel: 1, Beta: 1}}
You are expecting that the set should contain nodes with unique names, but nowhere do you specify that uniqueness should depend on the property value of those nodes.
You should add the following method to your node class:
def __hash__(self):
return hash(self.value)
There's a few issues, some related to a lack of type checking and some from the design of your class.
First, you have a Node class, instances of which you've kind of implied maybe should have a unique self.value, and that self.value is expected to always be a string (although these expectations are not contained in the code).
One problem causing the set() behavior, addressed in another comment, is the lack of a __hash__() method. Since it seems like you maybe want two Nodes to be equal if and only if their value parameter is the same string, adding
def __hash__(self):
return hash(self.value)
is needed. However, for set() to work like you want, you also need to add an __eq__() function.
def __eq__(self, other):
return isinstance(other, Node) and self.value == other.value
It's unclear to me whether the 'neighbors' attribute of a node should matter for its identity, as the terms node and graph don't carry information about what the classes actually are or represent, so maybe neighbors should be included in __eq__ too.
After adding those methods, the body of your loop is still incorrect. The problem line is graph.addVertex(Node(node1)) specifically the Node(node1). Supposedly that was intended to create a copy of node1, but it actually initializes a new node, where newnode.value is now an instance of Node, not a string. Using type hints and/or explicit type checking helps catch those problems, for example, adding a check for isinstance(value, str) to the initialization body.
Replacing those two conditionals from the loop body, the correct version would be:
if node1 not in graph.Nodes:
graph.addVertex(node1)
if node2 not in graph.Nodes:
graph.addVertex(node2)

After a certain amount of operations, the function suddenly "is not defined"

In my main method, when I try to test my insert function, after three inserts, the function suddenly throws an error saying it isn't defined.
I'm not really sure how to go about this. My assumption is that it has something to do with the space of the function being capped, and thus instead of going on with the remaining operations, the compiler cannot continue.
class MerkleTree:
def __init__ (self, rootHash, rootNode):
self.rootHash = rootHash
self.rootNode = rootNode
root = MerkleTree(None, None)
class MerkleNode():
def __init__ (self, value, left, right, leafValue):
self.value = value
self.left = left
self.right = right
self.leafValue = leafValue
class Entry():
def __init__ (self, key, value):
self.key = key
self.value = value
class MerkleTreeInterface:
#recursive Insert Helper
def insertHelp(self, root, node):
if (root.rootNode.right != None):
insertHelp(root.rootNode.right, node)
else:
root.rootNode.right = node
#insert function, finds the appropriate available slot to insert data
def insert(self, key, value):
entry = Entry(key, value)
node = MerkleNode(value, None, None, entry)
if(root.rootNode == None):
root.rootNode = node
else:
if(root.rootNode.left == None):
root.rootNode.left = node
elif(root.rootNode.right == None):
root.rootNode.right = node
else:
insertHelp(root, node)
class main():
tree = MerkleTreeInterface()
tree.insert("b", 2)
tree.insert("a", 1)
tree.insert("c", 3)
tree.insert("d", 4)
The expected result is to simply insert everything (so in this case, the list should be [a,b,c,d] when I traverse it (I only want the keys), but upon the 4th insertion, the error occurs. Here is the log:
Traceback (most recent call last):
File "/Users/User/Desktop/temp.py", line 75, in <module>
class main():
File "/Users/User/Desktop/temp.py", line 81, in main
tree.insert("d", 4)
File "/Users/User/Desktop/temp.py", line 42, in insert
insertHelp(root, node)
NameError: name 'insertHelp' is not defined
[Finished in 0.8s with exit code 1]
In the insertHelp method, insertHelp(root.rootNode.right, node) should be self.insertHelp(root.rootNode.right, node).
In the insert method, insertHelp(root, node) should be self.insertHelp(root, node).
You did not get this error while executing:
tree.insert("b", 2)
tree.insert("a", 1)
tree.insert("c", 3)
Because they did not execute insertHelp(root, node). But:
tree.insert("d", 4)
Tried to execute that statement and you got the error.
As the insertHelp method is an instance method, we need to use self.insertHelp to access it.
Search Python instance method vs Static method vs Class method to understand it clearly.

TypeError: 'Node' Object is not iterable

So I created this node class which has an array of children nodes. Now I want to iterate through the children to find the least cost/value total of all the possible paths. I'm applying the depth first search strategy. But after one of my children has undergone an interation, I get a TypeError saying that "NodeType cannot be iterated"
class Node:
def __init__(self, cost):
self.cost= cost
self.children = None
def get(self):
return self.cost
def findMinPath(self):
min_val = 10000
if self.children is None:
return self.cost
for child in self.children:
temp = child.findMinPath()
if temp<min_val:
min_val=temp
return min_val+self.cost
if __name__ =='__main__':
newnode = Node(0)
nodeleft= Node(5)
nodecenter=Node(3)
noderight=Node(6)
newnode.children={nodeleft,nodecenter,noderight}
nodeleft.children=(Node(4))
Nodecenterleft =Node(2)
Nodecenterright = Node(0)
nodecenter.children={Nodecenterleft,Nodecenterright}
Nodecenterleftleft=Node(1)
Nodecenterleft.children ={Nodecenterleftleft}
Nodecenterleftleftright= Node(1)
Nodecenterleftleft.children={Nodecenterleftleftright}
Nodecenterrightleft = Node(10)
Nodecenterright.children={Nodecenterrightleft}
Noderightleft=Node(1)
Noderightright=Node(5)
noderight.children ={Noderightleft,Noderightright}
print (newnode.findMinPath())
The stack trace is as follows:
Traceback (most recent call last):
File "/Users/yashshah/Desktop/Initializer/tree.py", line 45, in
print (newnode.findMinPath())
File "/Users/yashshah/Desktop/Initializer/tree.py", line 17, in findMinPath
temp = child.findMinPath()
File "/Users/yashshah/Desktop/Initializer/tree.py", line 16, in findMinPath
for child in self.children:
TypeError: 'Node' object is not iterable
[Finished in 0.094s]
This line is wrong:
nodeleft.children = (Node(4))
it needs to be:
nodeleft.children = {Node(4)}
Since you can put parens around any expression, Python can't be sure you mean to create a tuple with your version. So your line is the same as:
nodeleft.children = Node(4)
And as I expect you already see, your code then ends up thinking it's iterating over a collection of Node objects, but it's really trying to iterate over a single Node object, which isn't kosher.

int' object has no attribute '__getitem__' Python

This is the tree problem
class TreeProblem(Problem):
# methods exported to Search class ---------------------------------------------
# initial "state" of a tree is just its root
def initialState(self):
return self.root.id
# goal test is whether goal matches node label
def goalTest(self, state):
node = self.nodes[state]
return node.isgoal
# successors of a node are its children
def successorFn(self, state):
node = self.nodes[state]
if node.isTerminal():
return []
else:
return [self._contents('l', node.lchild), \
self._contents('r', node.rchild)]
# step cost state--[action]-->result is just the random cost associated with result
def stepCost(self, state, action, result):
node = self.nodes[result]
return node.cost
# no action is actually taken; we just print out the state for debugging
def takeAction(self, state, action):
print 'visit ', state
return 'visit', state
This is the Node class
class Node:
"""A node in a search tree. Contains a pointer to the parent (the node
that this is a successor of) and to the actual state for this node. Note
that if a state is arrived at by two paths, then there are two nodes with
the same state. Also includes the action that got us to this state, and
the total path_cost (also known as g) to reach the node. Other functions
may add an f and h value; see best_first_graph_search and astar_search for
an explanation of how the f and h values are handled. You will not need to
subclass this class."""
def __init__(self, state, parent=None, action=None, path_cost=0):
"Create a search tree Node, derived from a parent by an action."
# state = force_hashable(state)
self.update(self, state=state, parent=parent, action=action,
path_cost=path_cost, depth=0)
if parent:
self.depth = parent.depth + 1
def __repr__(self):
return "<Node %s>" % (self.state,)
def expand(self, problem):
"List the nodes reachable in one step from this node."
return [self.child_node(problem, action)
for action in problem.takeAction(self.state, self.action)]
#print problem
#return [Node(next, self, act,
# problem.stepCost(self.state, act, next[1]))
# for (act, next) in problem.successorFn(self.state)]
def child_node(self, problem, action):
"Fig. 3.10"
(act, next) = problem.successorFn(self.state)
print str(next[1]) + "\n"
return Node(next, self, action,
problem.stepCost(self.state, action, next[1]))
def solution(self):
"Return the sequence of actions to go from the root to this node."
return [node.action for node in self.path()[1:]]
def path(self):
"Return a list of nodes forming the path from the root to this node."
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def update(self, x, **entries):
"""Update a dict, or an object with slots, according to `entries` dict.
>>> update({'a': 1}, a=10, b=20)
{'a': 10, 'b': 20}
>>> update(Struct(a=1), a=10, b=20)
Struct(a=10, b=20)
"""
if isinstance(x, dict):
x.update(entries)
else:
x.__dict__.update(entries)
return x
# We want for a queue of nodes in breadth_first_search or
# astar_search to have no duplicated states, so we treat nodes
# with the same state as equal. [Problem: this may not be what you
# want in other contexts.]
def __eq__(self, other):
return isinstance(other, Node) and self.state == other.state
def __hash__(self):
return hash(str(self.state))
This is the dfs_search code:
def depth_limited_search(self, problem, limit=50):
return self.recursive_dls(Node(problem.initialState()), problem, limit)
def recursive_dls(self, node, problem, limit):
print str(type(node.state)) + "\n"
new_state=node.state
print new_state[1]
if problem.goalTest(node.state):
return node
elif node.depth == limit:
return 'cutoff'
else:
cutoff_occurred = False
for child in node.expand(problem):
result = self.recursive_dls(child, problem, limit)
if result == 'cutoff':
cutoff_occurred = True
elif result is not None:
return result
return if_(cutoff_occurred, 'cutoff', None)
here, node.state type is tuple
which has value ('r',2)
when i say node.state[1]
it gives int' object has no attribute 'getitem'
the above error
please guide here

Categories

Resources