def test_add_edge_edges(): ''' add_edge should connect existing nodes in the graph, causing neighbors to return the connected edges. add_edge should not overwrite existing edges and return False if the user tries. add_edge should create nodes if they do not already exist. ''' g = UndirectedGraph() # Edges can connect existing nodes assert g.add_node('a') assert g.add_node('b') assert g.add_edge('a', 'b') assert len(list(g.edges())) == 2 assert ('a', 'b', 1) in g.edges() assert ('b', 'a', 1) in g.edges() # Adding an edge that already exists should be rejected, and return False assert g.add_edge('a', 'b', 2) == False assert len(list(g.edges())) == 2 assert ('a', 'b', 1) in g.edges() assert ('b', 'a', 1) in g.edges() # Adding an edge with a non-existing node works just fine assert g.add_edge('b', 'c', 2) assert len(list(g.edges())) == 4 assert ('a', 'b', 1) in g.edges() assert ('b', 'a', 1) in g.edges() assert ('b', 'c', 2) in g.edges() assert ('c', 'b', 2) in g.edges()
def test_ignores_weight(): g = UndirectedGraph() g.add_edge('a', 'b', 1) g.add_edge('a', 'd', 20) g.add_edge('b', 'c', 1) g.add_edge('c', 'e', 1) g.add_edge('d', 'e', 20) found = breadth_first_search_by_criteria(g, 'a', criterion) assert found == ['a', 'd', 'e']
def test_graph_with_tie(): g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('b', 'd') g.add_edge('c', 'e') g.add_edge('d', 'e') found = breadth_first_search_by_criteria(g, 'a', criterion) assert found == ['a', 'b', 'c', 'e'] or found == ['a', 'b', 'd', 'e']
def test_single_path_undirected(): g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('b', 'd') g.add_edge('d', 'e') g.add_edge('e', 'f') assert depth_first_search_by_criteria(g, 'a', criterion) == ['a', 'b', 'd', 'e']
def test_single_path_undirected(): g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('b', 'd') g.add_edge('d', 'e') g.add_edge('e', 'f') assert breadth_first_search(g, 'a', 'e') == ['a', 'b', 'd', 'e']
def test_add_edge_contains(): ''' Adding an edge between non-existant edges should cause contains to report they exist. ''' g = UndirectedGraph() assert g.add_edge('a', 'b', 42) assert g.contains('a') assert g.contains('b')
def test_add_contains(): ''' Adding a node should cause contains to return true, adding a duplicate should return False, and contains should still report True for that node ''' g = UndirectedGraph() assert g.add_node('a') assert g.contains('a') assert g.add_node('a') == False assert g.contains('a')
def test_add_edge_nodes(): ''' Adding an edge between non-existant edges should cause those nodes to be returned by .nodes(). ''' g = UndirectedGraph() assert g.add_edge('a', 'b', 42) assert len(list(g.nodes())) == 2 assert 'a' in g.nodes() assert 'b' in g.nodes()
def test_no_path_undirected(): ''' Test BFS on a simple undirected graph that contains a no cycles, and no path to the goal. ''' g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('b', 'd') g.add_edge('e', 'f') assert breadth_first_search_by_criteria(g, 'a', criterion) is None
def test_multiple_paths_undirected(): g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('b', 'e') g.add_edge('b', 'd') g.add_edge('d', 'e') g.add_edge('e', 'f') found_path = depth_first_search_by_criteria(g, 'a', criterion) assert found_path == ['a', 'b', 'e'] or found_path == ['a', 'b', 'd', 'e']
def test_no_path_undirected_cycles(): ''' Test BFS on a simple undirected graph that contains cycles, but no path to the goal. ''' g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('c', 'a') g.add_edge('b', 'd') g.add_edge('e', 'f') assert breadth_first_search(g, 'a', 'e') is None
def test_single_path_with_cycles_undirected(): g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('c', 'h') g.add_edge('h', 'i') g.add_edge('i', 'j') g.add_edge('j', 'e') g.add_edge('b', 'd') g.add_edge('d', 'k') g.add_edge('k', 'f') g.add_edge('f', 'b') assert depth_first_search_by_criteria(g, 'a', criterion) == ['a', 'b', 'c', 'h', 'i', 'j', 'e']
def test_single_path_with_cycles_undirected(): g = UndirectedGraph() g.add_edge('a', 'b') g.add_edge('b', 'c') g.add_edge('c', 'h') g.add_edge('h', 'i') g.add_edge('i', 'j') g.add_edge('j', 'k') g.add_edge('b', 'd') g.add_edge('d', 'e') g.add_edge('e', 'f') g.add_edge('f', 'b') assert breadth_first_search(g, 'a', 'k') == ['a', 'b', 'c', 'h', 'i', 'j', 'k']
def test_add_nodes(): ''' Adding a node should cause that node to appear in the return value of .nodes(). ''' g = UndirectedGraph() assert g.add_node('a') assert 'a' in g.nodes() assert len(list(g.nodes())) == 1 assert g.add_node('a') == False assert 'a' in g.nodes() assert len(list(g.nodes())) == 1 assert g.add_node('b') assert 'a' in g.nodes() assert 'b' in g.nodes() assert len(list(g.nodes())) == 2
def construct_word_ladder_graph(word_list): ''' Given a list of words (all of which are assumed to be the same length) construct a graph that can be used to solve the word_ladder_problem. Specifically your graph should have a single node for every word in the word list, and an edge that connects nodes if the two words are different by exactly one letter. ''' g = UndirectedGraph() for w_idx, word in enumerate(word_list): for other in word_list[w_idx:]: assert len(word) == len(other) differences = 0 for i in range(len(word)): if word[i] != other[i]: differences += 1 if differences > 1: break if differences == 1: g.add_edge(word, other) return g
def test_simple_integration(): ''' test a simple use case, retesting assumptions at each step. ''' g = UndirectedGraph() assert g.add_node('a') assert g.contains('a') assert len(list(g.nodes())) == 1 assert 'a' in g.nodes() assert len(list(g.neighbors('a'))) == 0 assert g.add_node('b') assert g.contains('b') assert len(list(g.nodes())) == 2 assert 'a' in g.nodes() assert 'b' in g.nodes() assert len(list(g.neighbors('a'))) == 0 assert len(list(g.neighbors('b'))) == 0 assert g.add_node('c') assert g.contains('c') assert len(list(g.nodes())) == 3 assert 'a' in g.nodes() assert 'b' in g.nodes() assert 'c' in g.nodes() assert len(list(g.neighbors('a'))) == 0 assert len(list(g.neighbors('b'))) == 0 assert len(list(g.neighbors('c'))) == 0 g.add_edge('a', 'b') edges = list(g.edges()) assert len(edges) == 2 assert ('a', 'b', 1) in edges assert ('b', 'a', 1) in edges assert g.contains('a') assert g.contains('b') assert g.contains('c') assert len(list(g.nodes())) == 3 assert 'a' in g.nodes() assert 'b' in g.nodes() assert 'c' in g.nodes() assert len(list(g.neighbors('a'))) == 1 assert ('b', 1) in g.neighbors('a') assert len(list(g.neighbors('b'))) == 1 assert ('a', 1) in g.neighbors('b') assert len(list(g.neighbors('c'))) == 0 g.add_edge('a', 'c') edges = list(g.edges()) assert len(edges) == 4 assert ('a', 'b', 1) in edges assert ('b', 'a', 1) in edges assert ('a', 'c', 1) in edges assert ('c', 'a', 1) in edges assert g.contains('a') assert g.contains('b') assert g.contains('c') assert len(list(g.nodes())) == 3 assert 'a' in g.nodes() assert 'b' in g.nodes() assert 'c' in g.nodes() assert len(list(g.neighbors('a'))) == 2 assert ('b', 1) in g.neighbors('a') assert ('c', 1) in g.neighbors('a') assert len(list(g.neighbors('b'))) == 1 assert ('a', 1) in g.neighbors('b') assert len(list(g.neighbors('c'))) == 1 assert ('a', 1) in g.neighbors('c') edges = list(g.edges()) assert ('a', 'b', 1) in edges assert ('b', 'a', 1) in edges assert ('a', 'c', 1) in edges assert ('c', 'a', 1) in edges