def setUp(self): self.main_node = Node('Main Test Node') self.other_node = Node('Other Test Node') self.main_link = Link(self.other_node, 1) self.other_link = Link(self.main_node, 1) self.main_node.link_list.append(self.main_link) self.other_node.link_list.append(self.other_link)
def test_add_link_with_multiple_targets(self): additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') LINK_WEIGHT = 10 self.main_node.add_link([additional_node_1, additional_node_2], weight=LINK_WEIGHT) # Check that the links were added and have the correct weight new_link_1 = self.main_node.link_list[-2] self.assertEqual(new_link_1.target, additional_node_1) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = self.main_node.link_list[-1] self.assertEqual(new_link_2.target, additional_node_2) self.assertEqual(new_link_2.weight, LINK_WEIGHT)
def test_add_link_to_self_with_multiple_sources(self): LINK_WEIGHT = 1 additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') self.main_node.add_link_to_self([additional_node_1, additional_node_2], LINK_WEIGHT) # Check that the link was added and has the correct weight new_link_1 = additional_node_1.link_list[-1] self.assertEqual(new_link_1.target, self.main_node) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = additional_node_2.link_list[-1] self.assertEqual(new_link_2.target, self.main_node) self.assertEqual(new_link_2.weight, LINK_WEIGHT)
def setUp(self): self.test_graph = Graph() self.node_1 = Node('Node 1') self.node_2 = Node('Node 2') self.node_3 = Node('Node 3') self.test_graph.node_list.extend([ self.node_1, self.node_2, self.node_3]) self.node_1.link_list.append(Link(self.node_2, 234)) self.node_1.link_list.append(Link(self.node_3, 375)) self.node_2.link_list.append(Link(self.node_1, 124)) self.node_2.link_list.append(Link(self.node_3, 247)) self.node_3.link_list.append(Link(self.node_1, 123)) self.node_3.link_list.append(Link(self.node_2, 234))
def test_find_link(self): found_link = self.main_node.find_link(self.other_node) self.assertEqual(found_link, self.main_link) # Test target value not found should return None unlinked_to_node = Node("Node that isn't linked to") bad_found_link = self.main_node.find_link(unlinked_to_node) self.assertIsNone(bad_found_link)
def test_add_link_to_self_with_one_source(self): LINK_WEIGHT = 1 additional_node = Node('Additional Node') self.main_node.add_link_to_self(additional_node, LINK_WEIGHT) # Check that the link was added and has the correct weight new_link = additional_node.link_list[-1] self.assertEqual(new_link.target, self.main_node) self.assertEqual(new_link.weight, LINK_WEIGHT)
def test_add_link_with_one_target(self): additional_node = Node('Additional Node') LINK_WEIGHT = 10 self.main_node.add_link(additional_node, weight=LINK_WEIGHT) # Check that the link was added and has the correct weight new_link = self.main_node.link_list[-1] self.assertEqual(new_link.target, additional_node) self.assertEqual(new_link.weight, LINK_WEIGHT)
def test_add_reciprocal_link_with_one_target(self): LINK_WEIGHT = 1 additional_node = Node('Additional Node') self.main_node.add_reciprocal_link(additional_node, LINK_WEIGHT) # Test that both links were added new_link_1 = self.main_node.link_list[-1] self.assertEqual(new_link_1.target, additional_node) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = additional_node.link_list[-1] self.assertEqual(new_link_2.target, self.main_node) self.assertEqual(new_link_2.weight, LINK_WEIGHT)
def test_add_reciprocal_link_with_multiple_targets(self): LINK_WEIGHT = 1 additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') self.main_node.add_reciprocal_link( [additional_node_1, additional_node_2], LINK_WEIGHT) # Test that all links were added as expected # Test links in self.main_node new_link_1 = self.main_node.link_list[-2] self.assertEqual(new_link_1.target, additional_node_1) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = self.main_node.link_list[-1] self.assertEqual(new_link_2.target, additional_node_2) self.assertEqual(new_link_2.weight, LINK_WEIGHT) # Test links in additional_node_1 new_link_3 = additional_node_1.link_list[-1] self.assertEqual(new_link_3.target, self.main_node) self.assertEqual(new_link_3.weight, LINK_WEIGHT) # Test links in additional_node_2 new_link_4 = additional_node_2.link_list[-1] self.assertEqual(new_link_4.target, self.main_node) self.assertEqual(new_link_4.weight, LINK_WEIGHT)
def test_merge_links_from_with_merge_same_value_targets(self): new_node_with_existing_value = Node('Other Test Node') extra_test_link = Link(new_node_with_existing_value, 5) self.other_node.link_list.append(extra_test_link) self.main_node.merge_links_from(self.other_node, merge_same_value_targets=True) # Test that only one link was added to self.main_node self.assertEqual(len(self.main_node.link_list), 2) # Test that the weight of extra_test_link was added to self.main_link self.assertEqual(self.main_node.link_list[0], self.main_link) self.assertEqual(self.main_link.weight, 6) # Test that the added link is a new link, not the old link self.assertNotEqual(self.main_node.link_list[1], self.other_link) self.assertEqual(self.main_node.link_list[1].target, self.main_node) self.assertEqual(self.main_node.link_list[1].weight, 1)
def test_str(self): node = Node('Test Node') link = Link(node, 1) expected = ('node.Link instance pointing to node ' 'with value "Test Node" with weight 1') self.assertEqual(expected, link.__str__())
def test_add_nodes_with_multiple_nodes(self): self.test_graph.add_nodes([Node('Node 4'), Node('Node 5')]) self.assertEqual(len(self.test_graph.node_list), 5)
def test_add_nodes_with_one_node(self): self.test_graph.add_nodes(Node('Node 4')) self.assertEqual(len(self.test_graph.node_list), 4)
def test_remove_node_with_node_not_in_graph_does_nothing(self): node_not_in_graph = Node('Node not in the graph') self.test_graph.remove_node(node_not_in_graph) self.assertEqual(self.test_graph.node_list, [self.node_1, self.node_2, self.node_3])
class TestNode(unittest.TestCase): def setUp(self): self.main_node = Node('Main Test Node') self.other_node = Node('Other Test Node') self.main_link = Link(self.other_node, 1) self.other_link = Link(self.main_node, 1) self.main_node.link_list.append(self.main_link) self.other_node.link_list.append(self.other_link) def test_init(self): # since setUp() already calls init, just verify that it worked self.assertEqual(self.main_node.value, 'Main Test Node') self.assertFalse(self.main_node.self_destruct) self.assertEqual(self.main_node.link_list, [self.main_link]) def test_str(self): expected = """node.Node instance with value Main Test Node with 1 links: 0: 1 --> Other Test Node""" self.assertMultiLineEqual(expected, self.main_node.__str__()) def test_merge_links_from(self): extra_test_link = Link(self.other_node, 5) self.other_node.link_list.append(extra_test_link) self.main_node.merge_links_from(self.other_node) # Test that only one link was added to self.main_node self.assertEqual(len(self.main_node.link_list), 2) # Test that the weight of extra_test_link was added to self.main_link self.assertEqual(self.main_node.link_list[0], self.main_link) self.assertEqual(self.main_link.weight, 6) # Test that the added link is a new link, not the old link self.assertNotEqual(self.main_node.link_list[1], self.other_link) self.assertEqual(self.main_node.link_list[1].target, self.main_node) self.assertEqual(self.main_node.link_list[1].weight, 1) def test_merge_links_from_with_merge_same_value_targets(self): new_node_with_existing_value = Node('Other Test Node') extra_test_link = Link(new_node_with_existing_value, 5) self.other_node.link_list.append(extra_test_link) self.main_node.merge_links_from(self.other_node, merge_same_value_targets=True) # Test that only one link was added to self.main_node self.assertEqual(len(self.main_node.link_list), 2) # Test that the weight of extra_test_link was added to self.main_link self.assertEqual(self.main_node.link_list[0], self.main_link) self.assertEqual(self.main_link.weight, 6) # Test that the added link is a new link, not the old link self.assertNotEqual(self.main_node.link_list[1], self.other_link) self.assertEqual(self.main_node.link_list[1].target, self.main_node) self.assertEqual(self.main_node.link_list[1].weight, 1) def test_find_link(self): found_link = self.main_node.find_link(self.other_node) self.assertEqual(found_link, self.main_link) # Test target value not found should return None unlinked_to_node = Node("Node that isn't linked to") bad_found_link = self.main_node.find_link(unlinked_to_node) self.assertIsNone(bad_found_link) def test_add_link_with_one_target(self): additional_node = Node('Additional Node') LINK_WEIGHT = 10 self.main_node.add_link(additional_node, weight=LINK_WEIGHT) # Check that the link was added and has the correct weight new_link = self.main_node.link_list[-1] self.assertEqual(new_link.target, additional_node) self.assertEqual(new_link.weight, LINK_WEIGHT) def test_add_link_with_multiple_targets(self): additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') LINK_WEIGHT = 10 self.main_node.add_link([additional_node_1, additional_node_2], weight=LINK_WEIGHT) # Check that the links were added and have the correct weight new_link_1 = self.main_node.link_list[-2] self.assertEqual(new_link_1.target, additional_node_1) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = self.main_node.link_list[-1] self.assertEqual(new_link_2.target, additional_node_2) self.assertEqual(new_link_2.weight, LINK_WEIGHT) def test_add_link_to_existing_node(self): ADDED_LINK_WEIGHT = 10 original_link_weight = self.main_link.weight original_link_list_length = len(self.main_node.link_list) self.main_node.add_link(self.other_node, weight=ADDED_LINK_WEIGHT) # Check that main_node.link_list did not gain a link self.assertEqual(len(self.main_node.link_list), original_link_list_length) # Check that ADDED_LINK_WEIGHT was added to self.main_link.weight self.assertEqual(self.main_link.weight, original_link_weight + ADDED_LINK_WEIGHT) def test_add_link_to_self_with_one_source(self): LINK_WEIGHT = 1 additional_node = Node('Additional Node') self.main_node.add_link_to_self(additional_node, LINK_WEIGHT) # Check that the link was added and has the correct weight new_link = additional_node.link_list[-1] self.assertEqual(new_link.target, self.main_node) self.assertEqual(new_link.weight, LINK_WEIGHT) def test_add_link_to_self_with_multiple_sources(self): LINK_WEIGHT = 1 additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') self.main_node.add_link_to_self([additional_node_1, additional_node_2], LINK_WEIGHT) # Check that the link was added and has the correct weight new_link_1 = additional_node_1.link_list[-1] self.assertEqual(new_link_1.target, self.main_node) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = additional_node_2.link_list[-1] self.assertEqual(new_link_2.target, self.main_node) self.assertEqual(new_link_2.weight, LINK_WEIGHT) def test_add_reciprocal_link_with_one_target(self): LINK_WEIGHT = 1 additional_node = Node('Additional Node') self.main_node.add_reciprocal_link(additional_node, LINK_WEIGHT) # Test that both links were added new_link_1 = self.main_node.link_list[-1] self.assertEqual(new_link_1.target, additional_node) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = additional_node.link_list[-1] self.assertEqual(new_link_2.target, self.main_node) self.assertEqual(new_link_2.weight, LINK_WEIGHT) def test_add_reciprocal_link_with_multiple_targets(self): LINK_WEIGHT = 1 additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') self.main_node.add_reciprocal_link( [additional_node_1, additional_node_2], LINK_WEIGHT) # Test that all links were added as expected # Test links in self.main_node new_link_1 = self.main_node.link_list[-2] self.assertEqual(new_link_1.target, additional_node_1) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = self.main_node.link_list[-1] self.assertEqual(new_link_2.target, additional_node_2) self.assertEqual(new_link_2.weight, LINK_WEIGHT) # Test links in additional_node_1 new_link_3 = additional_node_1.link_list[-1] self.assertEqual(new_link_3.target, self.main_node) self.assertEqual(new_link_3.weight, LINK_WEIGHT) # Test links in additional_node_2 new_link_4 = additional_node_2.link_list[-1] self.assertEqual(new_link_4.target, self.main_node) self.assertEqual(new_link_4.weight, LINK_WEIGHT) def test_remove_links_to_self(self): # Manually add a link pointing from self.main_node to itself new_link = Link(self.main_node, 1) self.main_node.link_list.append(new_link) self.main_node.remove_links_to_self() self.assertFalse(self.main_node in [l.target for l in self.main_node.link_list]) def test_get_value(self): value = self.main_node.get_value() self.assertEqual(value, self.main_node.value)
def from_string(cls, source, distance_weights=None, merge_same_words=False, group_marker_opening='<<', group_marker_closing='>>'): """ Read a string and derive of ``Graph`` from it. Words and punctuation marks are made into nodes. Punctuation marks are split into separate nodes unless they fall between other non-punctuation marks. ``'hello, world'`` is split into ``'hello'``, ``','``, and ``'world'``, while ``'who's there?'`` is split into ``"who's"``, ``'there'``, and ``'?'``. To group arbitrary characters together into a single node (e.g. to make ``'hello, world!'``), surround the text in question with ``group_marker_opening`` and ``group_marker_closing``. With the default value, this would look like ``'<<hello, world!>>'``. It is recommended that the group markers not appear anywhere in the source text where they aren't meant to act as such to prevent unexpected behavior. The exact regex for extracting nodes is defined by: :: expression = r'{0}(.+){1}|([^\w\s]+)\B|([\S]+\b)'.format( ''.join('\\' + c for c in group_marker_opening), ''.join('\\' + c for c in group_marker_closing) ) Args: source (str): the string to derive the graph from distance_weights (dict): dict of relative indices corresponding with word weights. For example, if a dict entry is ``1: 1000`` this means that every word is linked to the word which follows it with a weight of 1000. ``-4: 350`` would mean that every word is linked to the 4th word behind it with a weight of 350. A key of ``0`` refers to the weight words get pointing to themselves. Keys pointing beyond the edge of the word list will wrap around the list. The default value for ``distance_weights`` is ``{1: 1}``. This means that each word gets equal weight to whatever word follows it. Consequently, if this default value is used and ``merge_same_words`` is ``False``, the resulting graph behavior will simply move linearly through the source, wrapping at the end to the beginning. merge_same_words (bool): if nodes which have the same value should be merged or not. group_marker_opening (str): The string used to mark the beginning of word groups. group_marker_closing (str): The string used to mark the end of word groups. It is strongly recommended that this be different than ``group_marker_opening`` to prevent unexpected behavior with the regex pattern. Returns: Graph Example: >>> graph = Graph.from_string('i have nothing to say and ' ... 'i am saying it and that is poetry.') >>> ' '.join(graph.pick().value for i in range(8)) # doctest: +SKIP 'using chance algorithmic in algorithmic art easier blur' """ if distance_weights is None: distance_weights = {1: 1} # Convert distance_weights to a sorted list of tuples # To make output node list order more predictable sorted_weights_list = sorted(distance_weights.items(), key=lambda i: i[0]) # regex that matches: # * Anything surrounded by # group_marker_opening and group_marker_closing, # * Groups of punctuation marks followed by whitespace # * Any continuous group of non-whitespace characters # followed by whitespace expression = r'{0}(.+){1}|([^\w\s]+)\B|([\S]+\b)'.format( ''.join('\\' + c for c in group_marker_opening), ''.join('\\' + c for c in group_marker_closing)) matches = re.findall(expression, source) # Un-tuple matches since we are only using groups to strip brackets # Is there a better way to do this? words = [next(t for t in match if t) for match in matches] if merge_same_words: # Ensure a 1:1 correspondence between words and nodes, # and that all links point to these nodes as well # Create nodes for every unique word temp_node_list = [] for word in words: if word not in (n.value for n in temp_node_list): temp_node_list.append(Node(word)) # Loop through words, attaching links to nodes which correspond # to the current word. Ensure links also point to valid # corresponding nodes in the node list. for i, word in enumerate(words): matching_node = next( (n for n in temp_node_list if n.value == word)) for key, weight in sorted_weights_list: # Wrap the index of edge items wrapped_index = (key + i) % len(words) target_word = words[wrapped_index] matching_target_node = next( (n for n in temp_node_list if n.value == target_word)) matching_node.add_link(matching_target_node, weight) else: # Create one node for every (not necessarily unique) word. temp_node_list = [Node(word) for word in words] for i, node in enumerate(temp_node_list): for key, weight in sorted_weights_list: # Wrap the index of edge items wrapped_index = (key + i) % len(temp_node_list) node.add_link(temp_node_list[wrapped_index], weight) graph = cls() graph.add_nodes(temp_node_list) return graph
def test_init(self): node = Node('Test Node') link = Link(node, 1) self.assertEqual(link.target, node) self.assertEqual(link.weight, 1)
class TestNode(unittest.TestCase): def setUp(self): self.main_node = Node('Main Test Node') self.other_node = Node('Other Test Node') self.main_link = Link(self.other_node, 1) self.other_link = Link(self.main_node, 1) self.main_node.link_list.append(self.main_link) self.other_node.link_list.append(self.other_link) def test_init(self): # since setUp() already calls init, just verify that it worked self.assertEqual(self.main_node.value, 'Main Test Node') self.assertFalse(self.main_node.self_destruct) self.assertEqual(self.main_node.link_list, [self.main_link]) def test_str(self): expected = """node.Node instance with value Main Test Node with 1 links: 0: 1 --> Other Test Node""" self.assertMultiLineEqual(expected, self.main_node.__str__()) def test_merge_links_from(self): extra_test_link = Link(self.other_node, 5) self.other_node.link_list.append(extra_test_link) self.main_node.merge_links_from(self.other_node) # Test that only one link was added to self.main_node self.assertEqual(len(self.main_node.link_list), 2) # Test that the weight of extra_test_link was added to self.main_link self.assertEqual(self.main_node.link_list[0], self.main_link) self.assertEqual(self.main_link.weight, 6) # Test that the added link is a new link, not the old link self.assertNotEqual(self.main_node.link_list[1], self.other_link) self.assertEqual(self.main_node.link_list[1].target, self.main_node) self.assertEqual(self.main_node.link_list[1].weight, 1) def test_merge_links_from_with_merge_same_value_targets(self): new_node_with_existing_value = Node('Other Test Node') extra_test_link = Link(new_node_with_existing_value, 5) self.other_node.link_list.append(extra_test_link) self.main_node.merge_links_from(self.other_node, merge_same_value_targets=True) # Test that only one link was added to self.main_node self.assertEqual(len(self.main_node.link_list), 2) # Test that the weight of extra_test_link was added to self.main_link self.assertEqual(self.main_node.link_list[0], self.main_link) self.assertEqual(self.main_link.weight, 6) # Test that the added link is a new link, not the old link self.assertNotEqual(self.main_node.link_list[1], self.other_link) self.assertEqual(self.main_node.link_list[1].target, self.main_node) self.assertEqual(self.main_node.link_list[1].weight, 1) def test_find_link(self): found_link = self.main_node.find_link(self.other_node) self.assertEqual(found_link, self.main_link) # Test target value not found should return None unlinked_to_node = Node("Node that isn't linked to") bad_found_link = self.main_node.find_link(unlinked_to_node) self.assertIsNone(bad_found_link) def test_add_link_with_one_target(self): additional_node = Node('Additional Node') LINK_WEIGHT = 10 self.main_node.add_link(additional_node, weight=LINK_WEIGHT) # Check that the link was added and has the correct weight new_link = self.main_node.link_list[-1] self.assertEqual(new_link.target, additional_node) self.assertEqual(new_link.weight, LINK_WEIGHT) def test_add_link_with_multiple_targets(self): additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') LINK_WEIGHT = 10 self.main_node.add_link([additional_node_1, additional_node_2], weight=LINK_WEIGHT) # Check that the links were added and have the correct weight new_link_1 = self.main_node.link_list[-2] self.assertEqual(new_link_1.target, additional_node_1) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = self.main_node.link_list[-1] self.assertEqual(new_link_2.target, additional_node_2) self.assertEqual(new_link_2.weight, LINK_WEIGHT) def test_add_link_to_existing_node(self): ADDED_LINK_WEIGHT = 10 original_link_weight = self.main_link.weight original_link_list_length = len(self.main_node.link_list) self.main_node.add_link(self.other_node, weight=ADDED_LINK_WEIGHT) # Check that main_node.link_list did not gain a link self.assertEqual(len(self.main_node.link_list), original_link_list_length) # Check that ADDED_LINK_WEIGHT was added to self.main_link.weight self.assertEqual(self.main_link.weight, original_link_weight + ADDED_LINK_WEIGHT) def test_add_link_to_self_with_one_source(self): LINK_WEIGHT = 1 additional_node = Node('Additional Node') self.main_node.add_link_to_self(additional_node, LINK_WEIGHT) # Check that the link was added and has the correct weight new_link = additional_node.link_list[-1] self.assertEqual(new_link.target, self.main_node) self.assertEqual(new_link.weight, LINK_WEIGHT) def test_add_link_to_self_with_multiple_sources(self): LINK_WEIGHT = 1 additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') self.main_node.add_link_to_self([additional_node_1, additional_node_2], LINK_WEIGHT) # Check that the link was added and has the correct weight new_link_1 = additional_node_1.link_list[-1] self.assertEqual(new_link_1.target, self.main_node) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = additional_node_2.link_list[-1] self.assertEqual(new_link_2.target, self.main_node) self.assertEqual(new_link_2.weight, LINK_WEIGHT) def test_add_reciprocal_link_with_one_target(self): LINK_WEIGHT = 1 additional_node = Node('Additional Node') self.main_node.add_reciprocal_link(additional_node, LINK_WEIGHT) # Test that both links were added new_link_1 = self.main_node.link_list[-1] self.assertEqual(new_link_1.target, additional_node) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = additional_node.link_list[-1] self.assertEqual(new_link_2.target, self.main_node) self.assertEqual(new_link_2.weight, LINK_WEIGHT) def test_add_reciprocal_link_with_multiple_targets(self): LINK_WEIGHT = 1 additional_node_1 = Node('Additional Node 1') additional_node_2 = Node('Additional Node 2') self.main_node.add_reciprocal_link( [additional_node_1, additional_node_2], LINK_WEIGHT) # Test that all links were added as expected # Test links in self.main_node new_link_1 = self.main_node.link_list[-2] self.assertEqual(new_link_1.target, additional_node_1) self.assertEqual(new_link_1.weight, LINK_WEIGHT) new_link_2 = self.main_node.link_list[-1] self.assertEqual(new_link_2.target, additional_node_2) self.assertEqual(new_link_2.weight, LINK_WEIGHT) # Test links in additional_node_1 new_link_3 = additional_node_1.link_list[-1] self.assertEqual(new_link_3.target, self.main_node) self.assertEqual(new_link_3.weight, LINK_WEIGHT) # Test links in additional_node_2 new_link_4 = additional_node_2.link_list[-1] self.assertEqual(new_link_4.target, self.main_node) self.assertEqual(new_link_4.weight, LINK_WEIGHT) def test_remove_links_to_self(self): # Manually add a link pointing from self.main_node to itself new_link = Link(self.main_node, 1) self.main_node.link_list.append(new_link) self.main_node.remove_links_to_self() self.assertFalse( self.main_node in [l.target for l in self.main_node.link_list]) def test_get_value(self): value = self.main_node.get_value() self.assertEqual(value, self.main_node.value)
def test_short_str(self): node = Node('Test Node') link = Link(node, 1) expected = ('1 --> Test Node') self.assertEqual(expected, link._short_str())