From f9b30cecb4987a24acfd4e7bd1fc730618d29261 Mon Sep 17 00:00:00 2001 From: bonanashelby Date: Thu, 8 Jun 2017 17:56:17 -0700 Subject: [PATCH 1/5] initial commit --- src/dijkstra.py | 5 +++++ src/test_dijkstra.py | 0 2 files changed, 5 insertions(+) create mode 100644 src/dijkstra.py create mode 100644 src/test_dijkstra.py diff --git a/src/dijkstra.py b/src/dijkstra.py new file mode 100644 index 0000000..d194f6f --- /dev/null +++ b/src/dijkstra.py @@ -0,0 +1,5 @@ +"""Dijkstra algorithm for our shortest path graph.""" +from weighted_graph import Weighted + + +def dijkstra(): diff --git a/src/test_dijkstra.py b/src/test_dijkstra.py new file mode 100644 index 0000000..e69de29 From d38a27ac12e3492f9a1e97db9d3997e691fa324a Mon Sep 17 00:00:00 2001 From: kurtrm Date: Thu, 8 Jun 2017 18:27:40 -0700 Subject: [PATCH 2/5] Studied, meditated, groked, pseudocoded dijkstra. --- src/dijkstra.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/dijkstra.py b/src/dijkstra.py index d194f6f..e2fbb61 100644 --- a/src/dijkstra.py +++ b/src/dijkstra.py @@ -1,5 +1,30 @@ """Dijkstra algorithm for our shortest path graph.""" from weighted_graph import Weighted +from priorityq import PriorityQueue -def dijkstra(): +def dijkstra(weighted_graph, start_node): + """Find the shortest path to nodes from starting node.""" + if not weighted_graph.has_node(start_node): + raise IndexError('Node not in this weighted graph.') + current_node = {start_node: 0} + peeped = [] # list of dictionaries + priorityq = PriorityQueue() + priorityq.insert(start_node.key, start_node.value) + while len(priorityq) > 0: + # current_node = priorityq.pop() + # look at that nodes neighbors + + # insert neighbors into the queue with priority of + # edge weight plus current node weight. + + # The priority queue automatically organizes them + # by the minimum value, so we're good there. + + # We've looked at both of the current nodes neighbors, + # so we're good to move on to the next node. + + # If the current node's weight is less than the one + # in the peeped list, swap them out. + + # continue From 958dd17fdf8c611d7f4bf3dc0df7aa6f8b07a565 Mon Sep 17 00:00:00 2001 From: kurtrm Date: Fri, 9 Jun 2017 18:03:21 -0700 Subject: [PATCH 3/5] Got the logic down but ran into an issue with our implementation of the priority queue. --- src/dijkstra.py | 33 +++++++++++++++------------------ src/priorityq.py | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/dijkstra.py b/src/dijkstra.py index e2fbb61..5aa6997 100644 --- a/src/dijkstra.py +++ b/src/dijkstra.py @@ -2,29 +2,26 @@ from weighted_graph import Weighted from priorityq import PriorityQueue +# {'A':{'B': 7, 'C': 9}, 'B': {'D': 2, 'E': 4}, 'C': {'F': 6}, 'D':{}, 'E': {}, 'F': {}} + def dijkstra(weighted_graph, start_node): """Find the shortest path to nodes from starting node.""" if not weighted_graph.has_node(start_node): raise IndexError('Node not in this weighted graph.') current_node = {start_node: 0} - peeped = [] # list of dictionaries + visited = {} priorityq = PriorityQueue() - priorityq.insert(start_node.key, start_node.value) + priorityq.insert(current_node, 0) while len(priorityq) > 0: - # current_node = priorityq.pop() - # look at that nodes neighbors - - # insert neighbors into the queue with priority of - # edge weight plus current node weight. - - # The priority queue automatically organizes them - # by the minimum value, so we're good there. - - # We've looked at both of the current nodes neighbors, - # so we're good to move on to the next node. - - # If the current node's weight is less than the one - # in the peeped list, swap them out. - - # continue + current_node = priorityq.pop() + next_nodes = weighted_graph[list(current_node.keys())[0]] + for key, value in next_nodes.items(): + distance_from_start_node = value + list(current_node.values())[0] + priorityq.insert( + {key: distance_from_start_node}, distance_from_start_node + ) + if key in visited and distance_from_start_node > visited[key]: + continue + visited.update({key: distance_from_start_node}) + return visited diff --git a/src/priorityq.py b/src/priorityq.py index 3ae9ec8..ff2d9ce 100644 --- a/src/priorityq.py +++ b/src/priorityq.py @@ -3,6 +3,25 @@ # [{1: 0}, {100: 1}, {33: 2}, {44: 3}, {2: 0}] + # def heapify(self, iterable): + # """Function that will be used in init and other methods.""" + # heap_list = iterable + # for item in heap_list[::-1]: + # item_index = heap_list.index(item) + # parent = (item_index - 1) // 2 + # while item_index > 0: + + # if list(heap_list[parent].values())[0] < list(heap_list[parent].values())[0]: + # curr_val = heap_list[parent] + # heap_list[parent] = heap_list[item_index] + # heap_list[item_index] = curr_val + # item_index = parent + # parent = (item_index - 1) // 2 + # else: + # break + # return heap_list + + class PriorityQueue(object): """Implement a priority queue.""" From e805a650112a0d57ee295edf3303317b21904ee7 Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 28 Jun 2017 13:39:32 -0700 Subject: [PATCH 4/5] Worked on Nick's comments. Also worked on refactoring tests. --- setup.py | 2 +- src/dll.py | 31 +++++++++++-------------------- src/priorityq.py | 15 ++++----------- src/test_dll.py | 48 +++++++++--------------------------------------- 4 files changed, 25 insertions(+), 71 deletions(-) diff --git a/setup.py b/setup.py index 97eb6a0..9a14157 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ extra_packages = { - 'testing': ['pytest', 'pytest-watch', 'pytest-cov', 'tox'] + 'testing': ['pytest-cov', 'tox'] } diff --git a/src/dll.py b/src/dll.py index 19c48b1..c67ed34 100644 --- a/src/dll.py +++ b/src/dll.py @@ -24,29 +24,27 @@ def push(self, val): """Push a value to the head of the list.""" if not val: raise TypeError('Please provide a not null value.') - self._length += 1 if self.tail is None and self.head is None: new_node = Node(val) - self.tail = new_node - self.head = new_node + self.tail = self.head = new_node else: new_node = Node(val, None, self.head) self.head.next_node = new_node self.head = new_node + self._length += 1 def append(self, val): """Append a val to the tail of a list.""" if not val: raise TypeError('Please provide a not null value.') - self._length += 1 if self.tail is None and self.head is None: new_node = Node(val) - self.tail = new_node - self.head = new_node + self.tail = self.head = new_node else: new_node = Node(val, self.tail, None) self.tail.prior_node = new_node self.tail = new_node + self._length += 1 def pop(self): """Pop pops from the head of the list.""" @@ -56,29 +54,25 @@ def pop(self): self._length -= 1 if self.head == self.tail: last_pop = self.head - self.head = None - self.tail = None + self.tail = self.head = None return last_pop.data popped = self.head self.head = self.head.prior_node - popped.prior_node = None self.head.next_node = None return popped.data def shift(self): """Remove the node from the tail of the list.""" - if not self.head: + if not self.tail: raise IndexError( 'There\'s nothing to remove from the linked list.') self._length -= 1 if self.head == self.tail: last_pop = self.head - self.head = None - self.tail = None + self.tail = self.head = None return last_pop.data shifted = self.tail self.tail = self.tail.next_node - shifted.next_node = None self.tail.prior_node = None return shifted.data @@ -88,13 +82,12 @@ def __len__(self): def remove(self, val): """Remove a node with the value provided.""" - if val is None: - raise TypeError( - 'That value is not in this particular linked list.') if self.head.data == val: self.pop() + return elif self.tail.data == val: self.shift() + return current_node = self.head while current_node is not None: if current_node.data != val: @@ -102,9 +95,7 @@ def remove(self, val): else: new_next_node = current_node.next_node new_prior_node = current_node.prior_node - current_node.next_node.prior_node = new_prior_node - current_node.prior_node.next_node = new_next_node - current_node.next_node = None - current_node.prior_node = None + new_next_node.next_node.prior_node = new_prior_node + new_prior_node.prior_node.next_node = new_next_node self._length -= 1 break diff --git a/src/priorityq.py b/src/priorityq.py index ff2d9ce..b7459a5 100644 --- a/src/priorityq.py +++ b/src/priorityq.py @@ -37,15 +37,8 @@ def heapify(self, iterable): parent = (item_index - 1) // 2 while item_index > 0: if list(heap_list[parent].values())[0] is 0 and list(heap_list[item_index].values())[0] is 0: - if list(heap_list[item_index].keys())[0] < list(heap_list[parent].keys())[0]: - curr_val = heap_list[parent] - heap_list[parent] = heap_list[item_index] - heap_list[item_index] = curr_val - item_index = parent - parent = (item_index - 1) // 2 - else: - item_index = parent - parent = (item_index - 1) // 2 + item_index = parent + parent = (item_index - 1) // 2 elif list(heap_list[parent].values())[0] > 0 and list(heap_list[item_index].values())[0] is 0: item_index = parent parent = (item_index - 1) // 2 @@ -71,8 +64,8 @@ def heapify(self, iterable): def insert(self, value, priority=0): """Insert a value into the priority queue with an optional priority.""" - if not isinstance(value, int) or not isinstance(priority, int): - raise TypeError("Must provide an integer for value and priority.") + if not isinstance(priority, int): + raise TypeError("Must provide an integer for priority.") if priority < 0: raise ValueError("You may not use a negative priority. Priority must be 0 or greater.") self._heap.append({value: priority}) diff --git a/src/test_dll.py b/src/test_dll.py index 36f412f..339804d 100644 --- a/src/test_dll.py +++ b/src/test_dll.py @@ -16,12 +16,6 @@ def test_dll_initialization(dll): assert dll.head is None -def test_dll_push_raises_type_error(dll): - """Test that the value error is raised.""" - with pytest.raises(TypeError): - dll.push() - - def test_dll_push_pushes_value(dll): """Test that the push pushes a value to head of list.""" dll.push(1) @@ -69,17 +63,10 @@ def test_dll_pop_only_has_one_item(dll): assert dll.tail is None -def test_dll_append_raises_type_error(dll): - """Test that we get a type error.""" - with pytest.raises(TypeError): - dll.append() - - def test_dll_appends_a_value(dll): """Ensure tail and head are the same.""" dll.append(1) - assert dll.tail.data == 1 - assert dll.head.data == 1 + assert dll.tail.data == dll.head.data == 1 def test_dll_appends_3_values(dll): @@ -113,17 +100,7 @@ def test_dll_shift_only_has_one_item(dll): assert dll.head.next_node is None assert dll.tail.prior_node is None assert dll.shift() == 2 - assert dll.head is None - assert dll.tail is None - - -def test_dll_remove_index_error(dll): - """Testing that the Index Error is raised if no val is passed.""" - dll.push(1) - dll.push(2) - dll.push(3) - with pytest.raises(TypeError): - dll.remove() + assert dll.head is dll.tail is None def test_dll_remove(dll): @@ -133,35 +110,28 @@ def test_dll_remove(dll): dll.push(3) dll.push(4) dll.remove(3) - assert dll.head.prior_node.data == 2 - assert dll.head.prior_node.next_node.data == 4 + assert (dll.head.prior_node.data, + dll.head.prior_node.next_node.data) == (2, 4) dll.remove(1) assert dll.tail.data == 2 assert dll.tail.next_node.data == 4 dll.remove(4) - assert dll.head.data == 2 - assert dll.tail.data == 2 + assert dll.head.data == dll.tail.data == 2 def test_dll_len(dll): """Test to make sure we get the right number of nodes.""" - assert len(dll) == 0 + dll_lengths = [] dll.push(1) - assert len(dll) == 1 dll.push(2) - assert len(dll) == 2 dll.append(3) - assert len(dll) == 3 dll.push(4) - assert len(dll) == 4 dll.push(5) - assert len(dll) == 5 dll.push(6) + dll_lengths.append(len(dll)) dll.remove(4) - assert len(dll) == 5 dll.pop() - assert len(dll) == 4 dll.shift() - assert len(dll) == 3 dll.pop() - assert len(dll) == 2 + dll_lengths.append(len(dll)) + assert dll_lengths == [5, 2] From 83fd1c0ccc34c1efedc0d148c45b6711d8ad4e6d Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 28 Jun 2017 17:31:18 -0700 Subject: [PATCH 5/5] got tox working, with coverage. --- .coveragerc | 31 +++++++++++++++ src/dll.py | 4 +- src/test_dll.py | 103 +++++++++++++++++++++++++++--------------------- tox.ini | 2 +- 4 files changed, 91 insertions(+), 49 deletions(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..2021d2b --- /dev/null +++ b/.coveragerc @@ -0,0 +1,31 @@ +[run] +source = + src/dll.py +omit = + src/binheap.py + src/deque.py + src/dijkstra.py + src/graph_1.py + src/graph_2.py + src/linked_list.py + src/priorityq.py + src/que_.py + src/reverse_linked_list.py + src/stack.py + src/test_dll.py + src/test_binheap.py + src/test_deque.py + src/test_dijkstra.py + src/test_graph.py + src/test_graph_2.py + src/test_linked_list.py + src/test_priority_que.py + src/test_que_.py + src/test_reverse_linked_list.py + src/test_stack.py + src/test_weighted_graph.py + src/test_weighted_traversal.py + src/weighted_graph.py + src/weighted_traversal.py +[report] +show_missing = True \ No newline at end of file diff --git a/src/dll.py b/src/dll.py index c67ed34..a148766 100644 --- a/src/dll.py +++ b/src/dll.py @@ -95,7 +95,7 @@ def remove(self, val): else: new_next_node = current_node.next_node new_prior_node = current_node.prior_node - new_next_node.next_node.prior_node = new_prior_node - new_prior_node.prior_node.next_node = new_next_node + new_next_node.prior_node = new_prior_node + new_prior_node.next_node = new_next_node self._length -= 1 break diff --git a/src/test_dll.py b/src/test_dll.py index 339804d..2b50ca7 100644 --- a/src/test_dll.py +++ b/src/test_dll.py @@ -12,23 +12,20 @@ def dll(): def test_dll_initialization(dll): """Test that there's nothing initialized.""" - assert dll.tail is None - assert dll.head is None + assert dll.tail is dll.head is None def test_dll_push_pushes_value(dll): """Test that the push pushes a value to head of list.""" dll.push(1) - assert dll.tail.data == 1 - assert dll.head.data == 1 + assert dll.tail.data == dll.head.data == 1 def test_dll_push_head_and_tail_change(dll): """Test if second item is pushed in. Head and tail are seperate values.""" dll.push(1) dll.push(2) - assert dll.tail.data == 1 - assert dll.head.data == 2 + assert (dll.tail.data, dll.head.data) == (1, 2) def test_dll_push_3(dll): @@ -36,12 +33,9 @@ def test_dll_push_3(dll): dll.push(1) dll.push(2) dll.push(3) - assert dll.tail.data == 1 - assert dll.head.prior_node.prior_node.data == 1 - assert dll.head != dll.head.prior_node - assert dll.head.data == 3 - assert dll.head.prior_node.next_node.data == 3 - assert dll.tail.next_node.data == 2 + assert (dll.tail.data, dll.head.prior_node.prior_node.data, + dll.head != dll.head.prior_node, dll.head.data, dll.head.prior_node.next_node.data, + dll.tail.next_node.data) == (1, 1, True, 3, 3, 2) def test_dll_pop_index_error(dll): @@ -50,17 +44,20 @@ def test_dll_pop_index_error(dll): dll.pop() -def test_dll_pop_only_has_one_item(dll): +def test_dll_pop_only_has_one_item_phase_one(dll): + """Test that pop only has one item and both are head and tail none vals.""" + dll.push(1) + dll.push(2) + assert (dll.pop(), dll.head.data, dll.tail.data, + dll.head.next_node) == (2, 1, 1, None) + + +def test_dll_pop_only_has_one_item_phase_two(dll): """Test that pop only has one item and both are head and tail none vals.""" dll.push(1) dll.push(2) - assert dll.pop() == 2 - assert dll.head.data == 1 - assert dll.tail.data == 1 - assert dll.head.next_node is None - assert dll.pop() == 1 - assert dll.head is None - assert dll.tail is None + dll.pop() + assert (dll.pop(), dll.head, dll.tail) == (1, None, None) def test_dll_appends_a_value(dll): @@ -74,36 +71,31 @@ def test_dll_appends_3_values(dll): dll.append(1) dll.append(2) dll.append(3) - assert dll.tail.data == 3 - assert dll.head.data == 1 - assert dll.head.next_node is None - assert dll.tail.prior_node is None - assert dll.tail.next_node.data == 2 - assert dll.head.prior_node.data == 2 - assert dll.head.prior_node.next_node.data == 1 - assert dll.tail.next_node.prior_node.data == 3 - - -def test_dll_shift_index_error(dll): - """Test that the Index Error is raised if no val is shifted.""" - with pytest.raises(IndexError): - dll.shift() + assert (dll.tail.data, dll.head.data, dll.head.next_node, + dll.tail.prior_node, dll.tail.next_node.data, + dll.head.prior_node.data, dll.head.prior_node.next_node.data, + dll.tail.next_node.prior_node.data) == (3, 1, None, + None, 2, 2, + 1, 3) -def test_dll_shift_only_has_one_item(dll): +def test_dll_shift_only_has_one_item_phase_one(dll): """Test that node connections after shifting.""" dll.push(1) dll.push(2) - assert dll.shift() == 1 - assert dll.head.data == 2 - assert dll.tail.data == 2 - assert dll.head.next_node is None - assert dll.tail.prior_node is None - assert dll.shift() == 2 - assert dll.head is dll.tail is None + assert (dll.shift(), dll.head.data, dll.tail.data, + dll.head.next_node, dll.tail.prior_node) == (1, 2, 2, None, None) -def test_dll_remove(dll): +def test_dll_shift_only_has_one_item_phase_two(dll): + """Test that node connections after shifting.""" + dll.push(1) + dll.push(2) + dll.shift() + assert (dll.shift(), dll.head, dll.tail) == (2, None, None) + + +def test_dll_remove_phase_one(dll): """Testing the dll remove function.""" dll.push(1) dll.push(2) @@ -112,9 +104,28 @@ def test_dll_remove(dll): dll.remove(3) assert (dll.head.prior_node.data, dll.head.prior_node.next_node.data) == (2, 4) + + +def test_dll_remove_phase_two(dll): + """Testing the dll remove function.""" + dll.push(1) + dll.push(2) + dll.push(3) + dll.push(4) + dll.remove(3) + dll.remove(1) + assert (dll.tail.data, + dll.tail.next_node.data) == (2, 4) + + +def test_dll_remove_phase_three(dll): + """Testing the dll remove function.""" + dll.push(1) + dll.push(2) + dll.push(3) + dll.push(4) + dll.remove(3) dll.remove(1) - assert dll.tail.data == 2 - assert dll.tail.next_node.data == 4 dll.remove(4) assert dll.head.data == dll.tail.data == 2 @@ -134,4 +145,4 @@ def test_dll_len(dll): dll.shift() dll.pop() dll_lengths.append(len(dll)) - assert dll_lengths == [5, 2] + assert dll_lengths == [6, 2] diff --git a/tox.ini b/tox.ini index 036b313..fa04b32 100644 --- a/tox.ini +++ b/tox.ini @@ -2,7 +2,7 @@ envlist = py27, py36 [testenv] -commands = py.test src --cov=src --cov-report term-missing +commands = pytest src/test_dll.py --cov=src --cov-report term-missing deps = pytest pytest-cov