python-graph-1.8.2/0000755000175000017500000000000012016145612013174 5ustar morphmorphpython-graph-1.8.2/tests/0000755000175000017500000000000012012025435014332 5ustar morphmorphpython-graph-1.8.2/tests/unittests-sorting.py0000644000175000017500000000601511345564450020450 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.algorithms.sorting """ import unittest import pygraph.classes from pygraph.algorithms.sorting import topological_sorting from pygraph.algorithms.searching import depth_first_search from sys import getrecursionlimit import testlib class test_topological_sorting(unittest.TestCase): def test_topological_sorting_on_tree(self): gr = testlib.new_graph() st, pre, post = depth_first_search(gr) tree = pygraph.classes.digraph.digraph() for each in st: if st[each]: if (each not in tree.nodes()): tree.add_node(each) if (st[each] not in tree.nodes()): tree.add_node(st[each]) tree.add_edge((st[each], each)) ts = topological_sorting(tree) for each in ts: if (st[each]): assert ts.index(each) > ts.index(st[each]) def test_topological_sorting_on_digraph(self): def is_ordered(node, list): # Has parent on list for each in list: if gr.has_edge((each, node)): return True # Has no possible ancestors on list st, pre, post = depth_first_search(gr, node) for each in list: if (each in st): return False return True gr = testlib.new_digraph() ts = topological_sorting(gr) while (ts): x = ts.pop() assert is_ordered(x, ts) def test_topological_sort_on_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,20001)) for i in range(0,20000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() topological_sorting(gr) assert getrecursionlimit() == recursionlimit if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-searching.py0000644000175000017500000001001211345314436020713 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.algorithms.searching """ # Imports import unittest import pygraph import pygraph.classes from pygraph.algorithms.searching import depth_first_search, breadth_first_search from sys import getrecursionlimit import testlib class test_depth_first_search(unittest.TestCase): def test_dfs_in_empty_graph(self): gr = pygraph.classes.graph.graph() st, pre, post = depth_first_search(gr) assert st == {} assert pre == [] assert post == [] def test_dfs_in_graph(self): gr = testlib.new_graph() st, pre, post = depth_first_search(gr) for each in gr: if (st[each] != None): assert pre.index(each) > pre.index(st[each]) assert post.index(each) < post.index(st[each]) for node in st: assert gr.has_edge((st[node], node)) or st[node] == None def test_dfs_in_empty_digraph(self): gr = pygraph.classes.digraph.digraph() st, pre, post = depth_first_search(gr) assert st == {} assert pre == [] assert post == [] def test_dfs_in_digraph(self): gr = testlib.new_digraph() st, pre, post = depth_first_search(gr) for each in gr: if (st[each] != None): assert pre.index(each) > pre.index(st[each]) assert post.index(each) < post.index(st[each]) for node in st: assert gr.has_edge((st[node], node)) or st[node] == None def test_dfs_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,20001)) for i in range(0,20000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() depth_first_search(gr, 0) assert getrecursionlimit() == recursionlimit class test_breadth_first_search(unittest.TestCase): def test_bfs_in_empty_graph(self): gr = pygraph.classes.graph.graph() st, lo = breadth_first_search(gr) assert st == {} assert lo == [] def test_bfs_in_graph(self): gr = pygraph.classes.graph.graph() gr = testlib.new_digraph() st, lo = breadth_first_search(gr) for each in gr: if (st[each] != None): assert lo.index(each) > lo.index(st[each]) for node in st: assert gr.has_edge((st[node], node)) or st[node] == None def test_bfs_in_empty_digraph(self): gr = pygraph.classes.digraph.digraph() st, lo = breadth_first_search(gr) assert st == {} assert lo == [] def test_bfs_in_digraph(self): gr = testlib.new_digraph() st, lo = breadth_first_search(gr) for each in gr: if (st[each] != None): assert lo.index(each) > lo.index(st[each]) for node in st: assert gr.has_edge((st[node], node)) or st[node] == None if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-readwrite.py0000644000175000017500000000756611351242520020751 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.algorithms.readwrite """ import unittest import pygraph from pygraph.readwrite import dot, markup import testlib def graph_equality(gr1, gr2): for each in gr1.nodes(): assert each in gr2.nodes() for each in gr2.nodes(): assert each in gr1.nodes() for each in gr1.edges(): assert each in gr2.edges() for each in gr2.edges(): assert each in gr1.edges() class test_readwrite_dot(unittest.TestCase): def test_dot_for_graph(self): gr = testlib.new_graph() dotstr = dot.write(gr) gr1 = dot.read(dotstr) dotstr = dot.write(gr1) gr2 = dot.read(dotstr) graph_equality(gr1, gr2) assert len(gr.nodes()) == len(gr1.nodes()) assert len(gr.edges()) == len(gr1.edges()) def test_dot_for_digraph(self): gr = testlib.new_digraph() dotstr = dot.write(gr) gr1 = dot.read(dotstr) dotstr = dot.write(gr1) gr2 = dot.read(dotstr) graph_equality(gr1, gr2) assert len(gr.nodes()) == len(gr1.nodes()) assert len(gr.edges()) == len(gr1.edges()) def test_dot_for_hypergraph(self): gr = testlib.new_hypergraph() dotstr = dot.write(gr) gr1 = dot.read_hypergraph(dotstr) dotstr = dot.write(gr1) gr2 = dot.read_hypergraph(dotstr) graph_equality(gr1, gr2) def test_output_names_in_dot(self): gr1 = testlib.new_graph() gr1.name = "Some name 1" gr2 = testlib.new_digraph() gr2.name = "Some name 2" gr3 = testlib.new_hypergraph() gr3.name = "Some name 3" assert "Some name 1" in dot.write(gr1) assert "Some name 2" in dot.write(gr2) assert "Some name 3" in dot.write(gr3) class test_readwrite_markup(unittest.TestCase): def test_xml_for_graph(self): gr = testlib.new_graph() dotstr = markup.write(gr) gr1 = markup.read(dotstr) dotstr = markup.write(gr1) gr2 = markup.read(dotstr) graph_equality(gr1, gr2) assert len(gr.nodes()) == len(gr1.nodes()) assert len(gr.edges()) == len(gr1.edges()) def test_xml_digraph(self): gr = testlib.new_digraph() dotstr = markup.write(gr) gr1 = markup.read(dotstr) dotstr = markup.write(gr1) gr2 = markup.read(dotstr) graph_equality(gr1, gr2) assert len(gr.nodes()) == len(gr1.nodes()) assert len(gr.edges()) == len(gr1.edges()) def test_xml_hypergraph(self): gr = testlib.new_hypergraph() dotstr = markup.write(gr) gr1 = markup.read(dotstr) dotstr = markup.write(gr1) gr2 = markup.read(dotstr) graph_equality(gr1, gr2) if __name__ == "__main__": unittest.main() python-graph-1.8.2/tests/unittests-pagerank.py0000644000175000017500000000654611423366477020572 0ustar morphmorph# Copyright (c) 2010 Pedro Matiello # Juarez Bochi # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for pygraph.algorithms.pagerank """ import unittest from pygraph.classes.digraph import digraph from pygraph.algorithms.pagerank import pagerank import testlib class test_pagerank(unittest.TestCase): # pagerank algorithm def test_pagerank_empty(self): #Test if an empty dict is returned for an empty graph G = digraph() self.assertEqual(pagerank(G), {}) def test_pagerank_cycle(self): #Test if all nodes in a cycle graph have the same value G = digraph() G.add_nodes([1, 2, 3, 4, 5]) G.add_edge((1, 2)) G.add_edge((2, 3)) G.add_edge((3, 4)) G.add_edge((4, 5)) G.add_edge((5, 1)) self.assertEqual(pagerank(G), {1: 0.2, 2: 0.2, 3: 0.2, 4: 0.2, 5: 0.2}) def test_pagerank(self): #Test example from wikipedia: http://en.wikipedia.org/wiki/File:Linkstruct3.svg G = digraph() G.add_nodes([1, 2, 3, 4, 5, 6, 7]) G.add_edge((1, 2)) G.add_edge((1, 3)) G.add_edge((1, 4)) G.add_edge((1, 5)) G.add_edge((1, 7)) G.add_edge((2, 1)) G.add_edge((3, 1)) G.add_edge((3, 2)) G.add_edge((4, 2)) G.add_edge((4, 3)) G.add_edge((4, 5)) G.add_edge((5, 1)) G.add_edge((5, 3)) G.add_edge((5, 4)) G.add_edge((5, 6)) G.add_edge((6, 1)) G.add_edge((6, 5)) G.add_edge((7, 5)) expected_pagerank = { 1: 0.280, 2: 0.159, 3: 0.139, 4: 0.108, 5: 0.184, 6: 0.061, 7: 0.069, } pr = pagerank(G) for k in pr: self.assertAlmostEqual(pr[k], expected_pagerank[k], places=3) def test_pagerank_random(self): G = testlib.new_digraph() md = 0.00001 df = 0.85 pr = pagerank(G, damping_factor=df, min_delta=md) min_value = (1.0-df)/len(G) for node in G: expected = min_value for each in G.incidents(node): expected += (df * pr[each] / len(G.neighbors(each))) assert abs(pr[node] - expected) < md if __name__ == "__main__": unittest.main() python-graph-1.8.2/tests/unittests-minmax.py0000644000175000017500000001676411677601557020300 0ustar morphmorph# Copyright (c) Pedro Matiello # Johannes Reinhardt # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.algorithms.searching """ import unittest import testlib from pygraph.classes.graph import graph from pygraph.classes.digraph import digraph from pygraph.algorithms.searching import depth_first_search from pygraph.algorithms.minmax import minimal_spanning_tree,\ shortest_path, heuristic_search, shortest_path_bellman_ford, maximum_flow, cut_tree from pygraph.algorithms.heuristics.chow import chow from pygraph.classes.exceptions import NegativeWeightCycleError from copy import deepcopy # helpers def tree_weight(gr, tree): sum = 0; for each in tree: sum = sum + gr.edge_weight((each, tree[each])) return sum def add_spanning_tree(gr, st): # A very tolerant implementation. gr.add_nodes(list(st.keys())) for each in st: if ((st[each] is not None) and (not gr.has_edge((st[each], each)))): # Accepts invalid STs gr.add_edge((st[each], each)) def bf_path(gr, root, target, remainder): if (remainder <= 0): return True if (root == target): return False for each in gr[root]: if (not bf_path(gr, each, target, remainder - gr.edge_weight((root, each)))): return False return True def generate_fixture_digraph(): #helper for bellman-ford algorithm G = digraph() G.add_nodes([1,2,3,4,5]) G.add_edge((1,2), 6) G.add_edge((1,4), 7) G.add_edge((2,4), 8) G.add_edge((3,2), -2) G.add_edge((4,3), -3) G.add_edge((2,5), -4) G.add_edge((4,5), 9) G.add_edge((5,1), 2) G.add_edge((5,3), 7) return G def generate_fixture_digraph_neg_weight_cycle(): #graph with a neg. weight cycle G = generate_fixture_digraph() G.del_edge((2,4)) G.add_edge((2,4), 2)#changed G.add_nodes([100,200]) #unconnected part G.add_edge((100,200),2) return G def generate_fixture_digraph_unconnected(): G = generate_fixture_digraph() G.add_nodes([100,200]) G.add_edge((100,200),2) return G # minimal spanning tree tests class test_minimal_spanning_tree(unittest.TestCase): def test_minimal_spanning_tree_on_graph(self): gr = testlib.new_graph(wt_range=(1,10)) mst = minimal_spanning_tree(gr, root=0) wt = tree_weight(gr, mst) len_dfs = len(depth_first_search(gr, root=0)[0]) for each in mst: if (mst[each] != None): mst_copy = deepcopy(mst) del(mst_copy[each]) for other in gr[each]: mst_copy[each] = other if (tree_weight(gr, mst_copy) < wt): gr2 = graph() add_spanning_tree(gr2, mst_copy) assert len(depth_first_search(gr2, root=0)[0]) < len_dfs # shortest path tests class test_shortest_path(unittest.TestCase): def test_shortest_path_on_graph(self): gr = testlib.new_graph(wt_range=(1,10)) st, dist = shortest_path(gr, 0) for each in gr: if (each in dist): assert bf_path(gr, 0, each, dist[each]) def test_shortest_path_on_digraph(self): # Test stub: not checking for correctness yet gr = testlib.new_digraph(wt_range=(1,10)) st, dist = shortest_path(gr, 0) for each in gr: if (each in dist): assert bf_path(gr, 0, each, dist[each]) def test_shortest_path_should_fail_if_source_does_not_exist(self): gr = testlib.new_graph() try: shortest_path(gr, 'invalid') assert False except (KeyError): pass class test_shortest_path_bellman_ford(unittest.TestCase): def test_shortest_path_BF_on_empty_digraph(self): pre, dist = shortest_path_bellman_ford(digraph(), 1) assert pre == {1:None} and dist == {1:0} def test_shortest_path_BF_on_digraph(self): #testing correctness on the fixture gr = generate_fixture_digraph() pre,dist = shortest_path_bellman_ford(gr, 1) assert pre == {1: None, 2: 3, 3: 4, 4: 1, 5: 2} \ and dist == {1: 0, 2: 2, 3: 4, 4: 7, 5: -2} def test_shortest_path_BF_on_digraph_with_negwcycle(self): #test negative weight cycle detection gr = generate_fixture_digraph_neg_weight_cycle() self.assertRaises(NegativeWeightCycleError, shortest_path_bellman_ford, gr, 1) def test_shortest_path_BF_on_unconnected_graph(self): gr = generate_fixture_digraph_unconnected() pre,dist = shortest_path_bellman_ford(gr, 100) assert pre == {200: 100, 100: None} and \ dist == {200: 2, 100: 0} class test_maxflow_mincut(unittest.TestCase): def test_trivial_maxflow(self): gr = digraph() gr.add_nodes([0,1,2,3]) gr.add_edge((0,1), wt=5) gr.add_edge((1,2), wt=3) gr.add_edge((2,3), wt=7) flows, cuts = maximum_flow(gr, 0, 3) assert flows[(0,1)] == 3 assert flows[(1,2)] == 3 assert flows[(2,3)] == 3 def test_random_maxflow(self): gr = testlib.new_digraph(wt_range=(1,20)) flows, cuts = maximum_flow(gr, 0, 1) # Sanity test for each in flows: assert gr.edge_weight(each) >= flows[each] # Tests for heuristic search are not necessary here as it's tested # in unittests-heuristics.py class test_cut_tree(unittest.TestCase): def test_cut_tree(self): #set up the graph (see example on wikipedia page for Gomory-Hu tree) gr = graph() gr.add_nodes([0,1,2,3,4,5]) gr.add_edge((0,1), wt=1) gr.add_edge((0,2), wt=7) gr.add_edge((1,3), wt=3) gr.add_edge((1,2), wt=1) gr.add_edge((1,4), wt=2) gr.add_edge((2,4), wt=4) gr.add_edge((3,4), wt=1) gr.add_edge((3,5), wt=6) gr.add_edge((4,5), wt=2) ct = cut_tree(gr) #check ct assert ct[(2,0)] == 8 assert ct[(4,2)] == 6 assert ct[(1,4)] == 7 assert ct[(3,1)] == 6 assert ct[(5,3)] == 8 def test_cut_tree_with_empty_graph(self): gr = graph() ct = cut_tree(gr) assert ct == {} def test_cut_tree_with_random_graph(self): gr = testlib.new_graph() ct = cut_tree(gr) if __name__ == "__main__": unittest.main() python-graph-1.8.2/tests/unittests-hypergraph.py0000644000175000017500000002164211532456371021137 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.classes.hypergraph """ import unittest import pygraph from pygraph.algorithms.generators import generate from pygraph.classes.exceptions import AdditionError from pygraph.classes.hypergraph import hypergraph import testlib from copy import copy, deepcopy class test_hypergraph(unittest.TestCase): # Add/Remove nodes and edges def test_raise_exception_on_duplicate_node_addition(self): gr = hypergraph() gr.add_node('a_node') try: gr.add_node('a_node') except AdditionError: pass else: fail() def test_raise_exception_on_duplicate_edge_link(self): gr = hypergraph() gr.add_node('a node') gr.add_hyperedge('an edge') gr.link('a node', 'an edge') try: gr.link('a node', 'an edge') except AdditionError: pass else: fail() def test_raise_exception_on_non_existing_link_removal(self): gr = hypergraph() gr.add_node(0) gr.add_hyperedge(1) try: gr.unlink(0, 1) except ValueError: pass else: fail() def test_raise_exception_when_edge_added_from_non_existing_node(self): gr = hypergraph() gr.add_nodes([0,1]) try: gr.link(3,0) except KeyError: pass else: fail() assert gr.neighbors(0) == [] def test_raise_exception_when_edge_added_to_non_existing_node(self): gr = hypergraph() gr.add_nodes([0,1]) try: gr.link(0,3) except KeyError: pass else: fail() assert gr.neighbors(0) == [] def test_remove_node(self): gr = testlib.new_hypergraph() gr.del_node(0) self.assertTrue(0 not in gr.nodes()) for e in gr.hyperedges(): for n in gr.links(e): self.assertTrue(n in gr.nodes()) def test_remove_edge(self): h = hypergraph() h.add_nodes([1,2]) h.add_edges(['a', 'b']) h.link(1,'a') h.link(2,'a') h.link(1,'b') h.link(2,'b') # Delete an edge h.del_edge('a') assert 1 == len(h.hyperedges()) gr = testlib.new_hypergraph() edge_no = len(gr.nodes())+1 gr.del_hyperedge(edge_no) self.assertTrue(edge_no not in gr.hyperedges()) def test_remove_link_from_node_to_same_node(self): gr = hypergraph() gr.add_node(0) gr.add_hyperedge(0) gr.link(0, 0) gr.unlink(0, 0) def test_remove_node_with_edge_to_itself(self): gr = hypergraph() gr.add_node(0) gr.add_hyperedge(0) gr.link(0, 0) gr.del_node(0) def test_check_add_node_s(self): gr = hypergraph() nodes = [1,2,3] gr.add_nodes(nodes) gr.add_node(0) for n in [0] + nodes: assert n in gr assert gr.has_node(n) def test_rank(self): # Uniform case gr = testlib.new_uniform_hypergraph(3) assert 3 == gr.rank() # Non-uniform case gr = testlib.new_hypergraph() num = max([len(gr.links(e)) for e in gr.hyperedges()]) assert num == gr.rank() def test_repr(self): """ Validate the repr string """ gr = testlib.new_hypergraph() gr_repr = repr(gr) assert isinstance(gr_repr, str ) assert gr.__class__.__name__ in gr_repr def test_order_len_equivlance(self): """ Verify the behavior of G.order() """ gr = testlib.new_hypergraph() assert len(gr) == gr.order() assert gr.order() == len( gr.node_links ) def test_hypergraph_equality_nodes(self): """ Hyperaph equality test. This one checks node equality. """ gr = hypergraph() gr.add_nodes([0,1,2,3,4,5]) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_node(5) gr4 = deepcopy(gr) gr4.add_node(6) gr4.del_node(0) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr def test_hypergraph_equality_edges(self): """ Hyperaph equality test. This one checks edge equality. """ gr = hypergraph() gr.add_nodes([0,1,2,3]) gr.add_edge('e1') gr.add_edge('e2') gr.link(0, 'e1') gr.link(1, 'e1') gr.link(1, 'e2') gr.link(2, 'e2') gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_edge('e2') gr4 = deepcopy(gr) gr4.unlink(1, 'e2') assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr def test_hypergraph_equality_labels(self): """ Hyperaph equality test. This one checks edge equality. """ gr = hypergraph() gr.add_nodes([0,1,2,3]) gr.add_edge('e1') gr.add_edge('e2') gr.add_edge('e3') gr.set_edge_label('e1', 'l1') gr.set_edge_label('e2', 'l2') gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.set_edge_label('e3', 'l3') gr4 = deepcopy(gr) gr4.set_edge_label('e1', 'lx') gr5 = deepcopy(gr) gr5.del_edge('e1') gr5.add_edge('e1') assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr assert gr != gr5 assert gr5 != gr def test_hypergraph_equality_attributes(self): """ Hyperaph equality test. This one checks edge equality. """ gr = hypergraph() gr.add_nodes([0,1]) gr.add_edge('e1') gr.add_edge('e2') gr.add_node_attribute(0, ('a',0)) gr.add_edge_attribute('e1', ('b',1)) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.add_node_attribute(0, ('x','y')) gr4 = deepcopy(gr) gr4.add_edge_attribute('e1', ('u','v')) gr5 = deepcopy(gr) gr5.del_edge('e1') gr5.add_edge('e1') gr6 = deepcopy(gr) gr6.del_node(0) gr6.add_node(0) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr assert gr != gr5 assert gr5 != gr assert gr != gr6 assert gr6 != gr def test_hypergraph_equality_weight(self): """ Hyperaph equality test. This one checks edge equality. """ gr = hypergraph() gr.add_nodes([0,1,2,3]) gr.add_edge('e1') gr.add_edge('e2') gr.add_edge('e3') gr.set_edge_weight('e1', 2) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.set_edge_weight('e3', 2) gr4 = deepcopy(gr) gr4.set_edge_weight('e1', 1) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr def test_hypergraph_link_unlink_link(self): """ Hypergraph link-unlink-link test. It makes sure that unlink cleans everything properly. No AdditionError should occur. """ h = hypergraph() h.add_nodes([1,2]) h.add_edges(['e1']) h.link(1, 'e1') h.unlink(1, 'e1') h.link(1,'e1') if __name__ == "__main__": unittest.main() python-graph-1.8.2/tests/unittests-heuristics.py0000644000175000017500000000650411276032451021142 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.algorithms.heuristics """ import unittest import pygraph from pygraph.classes.graph import graph from pygraph.classes.digraph import digraph from pygraph.algorithms.heuristics.euclidean import euclidean from pygraph.algorithms.heuristics.chow import chow from pygraph.classes import exceptions from test_data import nations_of_the_world class test_chow(unittest.TestCase): def setUp(self): self.G = graph() nations_of_the_world(self.G) def test_basic(self): """ Test some very basic functionality """ englands_neighbors = self.G.neighbors("England") assert set(['Wales', 'Scotland', 'France', 'Ireland']) == set( englands_neighbors ) def test_chow(self): heuristic = chow( "Wales", "North Korea", "Russia" ) heuristic.optimize(self.G) result = pygraph.algorithms.minmax.heuristic_search( self.G, "England", "India", heuristic ) def test_chow_unreachable(self): heuristic = chow( "Wales", "North Korea", "Russia" ) self.G.add_node("Sealand") self.G.add_edge(("England", "Sealand")) heuristic.optimize(self.G) self.G.del_edge(("England", "Sealand")) try: result = pygraph.algorithms.minmax.heuristic_search( self.G, "England", "Sealand" , heuristic ) except exceptions.NodeUnreachable as _: return assert False, "This test should raise an unreachable error." class test_euclidean(unittest.TestCase): def setUp(self): self.G = pygraph.classes.graph.graph() self.G.add_node('A', [('position',[0,0])]) self.G.add_node('B', [('position',[2,0])]) self.G.add_node('C', [('position',[2,3])]) self.G.add_node('D', [('position',[1,2])]) self.G.add_edge(('A', 'B'), wt=4) self.G.add_edge(('A', 'D'), wt=5) self.G.add_edge(('B', 'C'), wt=9) self.G.add_edge(('D', 'C'), wt=2) def test_euclidean(self): heuristic = euclidean() heuristic.optimize(self.G) result = pygraph.algorithms.minmax.heuristic_search(self.G, 'A', 'C', heuristic ) assert result == ['A', 'D', 'C'] if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-graph.py0000644000175000017500000002355311377117541020072 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.classes.Graph """ import unittest import pygraph from pygraph.algorithms.generators import generate from pygraph.classes.exceptions import AdditionError from pygraph.classes.graph import graph import testlib from copy import copy, deepcopy class test_graph(unittest.TestCase): # Add/Remove nodes and edges def test_raise_exception_on_duplicate_node_addition(self): gr = graph() gr.add_node('a_node') try: gr.add_node('a_node') except AdditionError: pass else: fail() def test_raise_exception_on_duplicate_edge_addition(self): gr = graph() gr.add_node('a_node') gr.add_node('other_node') gr.add_edge(("a_node","other_node")) try: gr.add_edge(("a_node","other_node")) except AdditionError: pass else: fail() def test_raise_exception_when_edge_added_from_non_existing_node(self): gr = graph() gr.add_nodes([0,1]) try: gr.add_edge((3,0)) except KeyError: pass else: fail() assert gr.node_neighbors == {0: [], 1: []} def test_raise_exception_when_edge_added_to_non_existing_node(self): gr = graph() gr.add_nodes([0,1]) try: gr.add_edge((0,3)) except KeyError: pass else: fail() assert gr.node_neighbors == {0: [], 1: []} def test_remove_node(self): gr = testlib.new_graph() gr.del_node(0) self.assertTrue(0 not in gr) for each, other in gr.edges(): self.assertTrue(each in gr) self.assertTrue(other in gr) def test_remove_edge_from_node_to_same_node(self): gr = graph() gr.add_node(0) gr.add_edge((0, 0)) gr.del_edge((0, 0)) def test_remove_node_with_edge_to_itself(self): gr = graph() gr.add_node(0) gr.add_edge((0, 0)) gr.del_node(0) def test_edges_between_different_nodes_should_be_arrows_in_both_ways(self): gr = graph() gr.add_nodes([0,1]) gr.add_edge((0,1), label="label", attrs=[('key','value')]) assert (0,1) in gr.edges() assert (1,0) in gr.edges() assert len(gr.edges()) == 2 assert gr.neighbors(0) == [1] assert gr.neighbors(1) == [0] assert (0,1) in gr.edge_properties.keys() assert (1,0) in gr.edge_properties.keys() assert (0,1) in gr.edge_attr.keys() assert (1,0) in gr.edge_attr.keys() def test_edges_between_different_nodes_should_be_a_single_arrow(self): gr = graph() gr.add_node(0) gr.add_edge((0,0), label="label", attrs=[('key','value')]) assert (0,0) in gr.edges() assert len(gr.edges()) == 1 assert gr.neighbors(0) == [0] assert (0,0) in gr.edge_properties.keys() assert (0,0) in gr.edge_attr.keys() assert len(gr.edge_attr[(0,0)]) == 1 # Invert graph def test_invert_graph(self): gr = testlib.new_graph() inv = gr.inverse() for each in gr.edges(): self.assertTrue(each not in inv.edges()) for each in inv.edges(): self.assertTrue(each not in gr.edges()) def test_invert_empty_graph(self): gr = graph() inv = gr.inverse() self.assertTrue(gr.nodes() == []) self.assertTrue(gr.edges() == []) # Complete graph def test_complete_graph(self): gr = graph() gr.add_nodes(range(10)) gr.complete() for i in range(10): for j in range(10): self.assertTrue((i, j) in gr.edges() or i == j) def test_complete_empty_graph(self): gr = graph() gr.complete() self.assertTrue(gr.nodes() == []) self.assertTrue(gr.edges() == []) def test_complete_graph_with_one_node(self): gr = graph() gr.add_node(0) gr.complete() self.assertTrue(gr.nodes() == [0]) self.assertTrue(gr.edges() == []) # Add graph def test_add_graph(self): gr1 = testlib.new_graph() gr2 = testlib.new_graph() gr1.add_graph(gr2) for each in gr2.nodes(): self.assertTrue(each in gr1) for each in gr2.edges(): self.assertTrue(each in gr1.edges()) def test_add_empty_graph(self): gr1 = testlib.new_graph() gr1c = copy(gr1) gr2 = graph() gr1.add_graph(gr2) self.assertTrue(gr1.nodes() == gr1c.nodes()) self.assertTrue(gr1.edges() == gr1c.edges()) # Add spanning tree def test_add_spanning_tree(self): gr = graph() st = {0: None, 1: 0, 2:0, 3: 1, 4: 2, 5: 3} gr.add_spanning_tree(st) for each in st: self.assertTrue((each, st[each]) in gr.edges() or (each, st[each]) == (0, None)) self.assertTrue((st[each], each) in gr.edges() or (each, st[each]) == (0, None)) def test_add_empty_spanning_tree(self): gr = graph() st = {} gr.add_spanning_tree(st) self.assertTrue(gr.nodes() == []) self.assertTrue(gr.edges() == []) def test_repr(self): """ Validate the repr string """ gr = testlib.new_graph() gr_repr = repr(gr) assert isinstance(gr_repr, str ) assert gr.__class__.__name__ in gr_repr def test_order_len_equivlance(self): """ Verify the behavior of G.order() """ gr = testlib.new_graph() assert len(gr) == gr.order() assert gr.order() == len( gr.node_neighbors ) def test_graph_equality_nodes(self): """ Graph equality test. This one checks node equality. """ gr = graph() gr.add_nodes([0,1,2,3,4,5]) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_node(5) gr4 = deepcopy(gr) gr4.add_node(6) gr4.del_node(0) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr def test_graph_equality_edges(self): """ Graph equality test. This one checks edge equality. """ gr = graph() gr.add_nodes([0,1,2,3,4]) gr.add_edge((0,1), wt=1) gr.add_edge((0,2), wt=2) gr.add_edge((1,2), wt=3) gr.add_edge((3,4), wt=4) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_edge((0,2)) gr4 = deepcopy(gr) gr4.add_edge((2,4)) gr5 = deepcopy(gr) gr5.del_edge((0,2)) gr5.add_edge((2,4)) gr6 = deepcopy(gr) gr6.del_edge((0,2)) gr6.add_edge((0,2), wt=10) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr assert gr != gr5 assert gr5 != gr assert gr != gr6 assert gr6 != gr def test_graph_equality_labels(self): """ Graph equality test. This one checks node equality. """ gr = graph() gr.add_nodes([0,1,2]) gr.add_edge((0,1), label="l1") gr.add_edge((1,2), label="l2") gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_edge((0,1)) gr3.add_edge((0,1)) gr4 = deepcopy(gr) gr4.del_edge((0,1)) gr4.add_edge((0,1), label="l3") assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr def test_graph_equality_attributes(self): """ Graph equality test. This one checks node equality. """ gr = graph() gr.add_nodes([0,1,2]) gr.add_edge((0,1)) gr.add_node_attribute(1, ('a','x')) gr.add_node_attribute(2, ('b','y')) gr.add_edge_attribute((0,1), ('c','z')) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_edge((0,1)) gr3.add_edge((0,1)) gr4 = deepcopy(gr) gr4.del_edge((0,1)) gr4.add_edge((0,1)) gr4.add_edge_attribute((0,1), ('d','k')) gr5 = deepcopy(gr) gr5.del_node(2) gr5.add_node(2) gr5.add_node_attribute(0, ('d','k')) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr assert gr != gr5 assert gr5 != gr if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-filters.py0000644000175000017500000001146711276032451020434 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ python-graph Unit tests for python-graph """ # Imports import unittest import pygraph from pygraph.algorithms.searching import depth_first_search, breadth_first_search from pygraph.classes.graph import graph from pygraph.algorithms.filters.radius import radius from pygraph.algorithms.filters.find import find import testlib class test_find_filter(unittest.TestCase): def test_bfs_in_empty_graph(self): gr = graph() st, lo = breadth_first_search(gr, filter=find(5)) assert st == {} assert lo == [] def test_bfs_in_graph(self): gr = testlib.new_graph() gr.add_node('find-me') gr.add_edge((0, 'find-me')) st, lo = breadth_first_search(gr, root=0, filter=find('find-me')) assert st['find-me'] == 0 for each in st: assert st[each] == None or st[each] == 0 or st[st[each]] == 0 def test_bfs_in_digraph(self): gr = testlib.new_digraph() gr.add_node('find-me') gr.add_edge((0, 'find-me')) st, lo = breadth_first_search(gr, root=0, filter=find('find-me')) assert st['find-me'] == 0 for each in st: assert st[each] == None or st[each] == 0 or st[st[each]] == 0 def test_dfs_in_empty_graph(self): gr = graph() st, pre, post = depth_first_search(gr) assert st == {} assert pre == [] assert post == [] def test_dfs_in_graph(self): gr = testlib.new_graph() gr.add_node('find-me') gr.add_node('dont-find-me') gr.add_edge((0, 'find-me')) gr.add_edge(('find-me','dont-find-me')) st, pre, post = depth_first_search(gr, root=0, filter=find('find-me')) assert st['find-me'] == 0 assert 'dont-find-me' not in st def test_dfs_in_digraph(self): gr = testlib.new_digraph() gr.add_node('find-me') gr.add_node('dont-find-me') gr.add_edge((0, 'find-me')) gr.add_edge(('find-me','dont-find-me')) st, pre, post = depth_first_search(gr, root=0, filter=find('find-me')) assert st['find-me'] == 0 assert 'dont-find-me' not in st class test_radius_filter(unittest.TestCase): def testbfs_in_empty_graph(self): gr = graph() st, lo = breadth_first_search(gr, filter=radius(2)) assert st == {} assert lo == [] def test_bfs_in_graph(self): gr = testlib.new_graph() st, lo = breadth_first_search(gr, root=0, filter=radius(3)) for each in st: assert (st[each] == None or st[each] == 0 or st[st[each]] == 0 or st[st[st[each]]] == 0) def test_bfs_in_digraph(self): gr = testlib.new_digraph() st, lo = breadth_first_search(gr, root=0, filter=radius(3)) for each in st: assert (st[each] == None or st[each] == 0 or st[st[each]] == 0 or st[st[st[each]]] == 0) def test_dfs_in_empty_graph(self): gr = graph() st, pre, post = depth_first_search(gr, filter=radius(2)) assert st == {} assert pre == [] assert post == [] def test_dfs_in_graph(self): gr = testlib.new_graph() st, pre, post = depth_first_search(gr, root=0, filter=radius(3)) for each in st: assert (st[each] == None or st[each] == 0 or st[st[each]] == 0 or st[st[st[each]]] == 0) def test_dfs_in_digraph(self): gr = testlib.new_graph() st, pre, post = depth_first_search(gr, root=0, filter=radius(3)) for each in st: assert (st[each] == None or st[each] == 0 or st[st[each]] == 0 or st[st[st[each]]] == 0) if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-digraph.py0000644000175000017500000002374311324116151020374 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.classes.Digraph """ import unittest import pygraph from pygraph.algorithms.generators import generate from pygraph.classes.exceptions import AdditionError from pygraph.classes.digraph import digraph from pygraph.classes.graph import graph import testlib from copy import copy, deepcopy class test_digraph(unittest.TestCase): # Add/Remove nodes and edges def test_raise_exception_on_duplicate_node_addition(self): gr = digraph() gr.add_node('a_node') try: gr.add_node('a_node') except AdditionError: pass else: fail() def test_raise_exception_on_duplicate_edge_addition(self): gr = digraph() gr.add_node('a_node') gr.add_node('other_node') gr.add_edge(("a_node","other_node")) try: gr.add_edge(("a_node","other_node")) except AdditionError: pass else: fail() def test_raise_exception_when_edge_added_from_non_existing_node(self): gr = digraph() gr.add_nodes([0,1]) try: gr.add_edge((3,0)) except AdditionError: pass else: self.fail("The graph allowed an edge to be added from a non-existing node.") assert gr.node_neighbors == {0: [], 1: []} assert gr.node_incidence == {0: [], 1: []} def test_raise_exception_when_edge_added_to_non_existing_node(self): gr = digraph() gr.add_nodes([0,1]) try: gr.add_edge((0,3)) except AdditionError: pass else: self.fail("TThe graph allowed an edge to be added to a non-existing node.") assert gr.node_neighbors == {0: [], 1: []} assert gr.node_incidence == {0: [], 1: []} def test_remove_node(self): gr = testlib.new_digraph() gr.del_node(0) self.assertTrue(0 not in gr) for (each, other) in gr.edges(): self.assertTrue(each in gr) self.assertTrue(other in gr) def test_remove_edge_from_node_to_same_node(self): gr = digraph() gr.add_node(0) gr.add_edge((0, 0)) gr.del_edge((0, 0)) def test_remove_node_with_edge_to_itself(self): gr = digraph() gr.add_node(0) gr.add_edge((0, 0)) gr.del_node(0) # Invert graph def test_invert_digraph(self): gr = testlib.new_digraph() inv = gr.inverse() for each in gr.edges(): self.assertTrue(each not in inv.edges()) for each in inv.edges(): self.assertTrue(each not in gr.edges()) def test_invert_empty_digraph(self): gr = digraph() inv = gr.inverse() self.assertTrue(gr.nodes() == []) self.assertTrue(gr.edges() == []) # Reverse graph def test_reverse_digraph(self): gr = testlib.new_digraph() rev = gr.reverse() for (u, v) in gr.edges(): self.assertTrue((v, u) in rev.edges()) for (u, v) in rev.edges(): self.assertTrue((v, u) in gr.edges()) def test_invert_empty_digraph(self): gr = digraph() rev = gr.reverse() self.assertTrue(rev.nodes() == []) self.assertTrue(rev.edges() == []) # Complete graph def test_complete_digraph(self): gr = digraph() gr.add_nodes(range(10)) gr.complete() for i in range(10): for j in range(10): self.assertTrue((i, j) in gr.edges() or i == j) def test_complete_empty_digraph(self): gr = digraph() gr.complete() self.assertTrue(gr.nodes() == []) self.assertTrue(gr.edges() == []) def test_complete_digraph_with_one_node(self): gr = digraph() gr.add_node(0) gr.complete() self.assertTrue(gr.nodes() == [0]) self.assertTrue(gr.edges() == []) # Add graph def test_add_digraph(self): gr1 = testlib.new_digraph() gr2 = testlib.new_digraph() gr1.add_graph(gr2) for each in gr2.nodes(): self.assertTrue(each in gr1) for each in gr2.edges(): self.assertTrue(each in gr1.edges()) def test_add_empty_digraph(self): gr1 = testlib.new_digraph() gr1c = copy(gr1) gr2 = digraph() gr1.add_graph(gr2) self.assertTrue(gr1.nodes() == gr1c.nodes()) self.assertTrue(gr1.edges() == gr1c.edges()) def test_add_graph_into_diagraph(self): d = digraph() g = graph() A = "A" B = "B" g.add_node( A ) g.add_node( B ) g.add_edge( (A,B) ) d.add_graph( g ) assert d.has_node( A ) assert d.has_node( B ) assert d.has_edge( (A,B) ) assert d.has_edge( (B,A) ) # Add spanning tree def test_add_spanning_tree(self): gr = digraph() st = {0: None, 1: 0, 2:0, 3: 1, 4: 2, 5: 3} gr.add_spanning_tree(st) for each in st: self.assertTrue((st[each], each) in gr.edges() or (each, st[each]) == (0, None)) def test_add_empty_spanning_tree(self): gr = digraph() st = {} gr.add_spanning_tree(st) self.assertTrue(gr.nodes() == []) self.assertTrue(gr.edges() == []) def test_repr(self): """ Validate the repr string """ gr = testlib.new_graph() gr_repr = repr(gr) assert isinstance(gr_repr, str ) assert gr.__class__.__name__ in gr_repr def test_order_len_equivlance(self): """ Verify the behavior of G.order() """ gr = testlib.new_graph() assert len(gr) == gr.order() assert gr.order() == len( gr.node_neighbors ) def test_digraph_equality_nodes(self): """ Digraph equality test. This one checks node equality. """ gr = digraph() gr.add_nodes([0,1,2,3,4,5]) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_node(5) gr4 = deepcopy(gr) gr4.add_node(6) gr4.del_node(0) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr def test_digraph_equality_edges(self): """ Digraph equality test. This one checks edge equality. """ gr = digraph() gr.add_nodes([0,1,2,3,4]) gr.add_edge((0,1), wt=1) gr.add_edge((0,2), wt=2) gr.add_edge((1,2), wt=3) gr.add_edge((3,4), wt=4) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_edge((0,2)) gr4 = deepcopy(gr) gr4.add_edge((2,4)) gr5 = deepcopy(gr) gr5.del_edge((0,2)) gr5.add_edge((2,4)) gr6 = deepcopy(gr) gr6.del_edge((0,2)) gr6.add_edge((0,2), wt=10) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr assert gr != gr5 assert gr5 != gr assert gr != gr6 assert gr6 != gr def test_digraph_equality_labels(self): """ Digraph equality test. This one checks node equality. """ gr = digraph() gr.add_nodes([0,1,2]) gr.add_edge((0,1), label="l1") gr.add_edge((1,2), label="l2") gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_edge((0,1)) gr3.add_edge((0,1)) gr4 = deepcopy(gr) gr4.del_edge((0,1)) gr4.add_edge((0,1), label="l3") assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr def test_digraph_equality_attributes(self): """ Digraph equality test. This one checks node equality. """ gr = digraph() gr.add_nodes([0,1,2]) gr.add_edge((0,1)) gr.add_node_attribute(1, ('a','x')) gr.add_node_attribute(2, ('b','y')) gr.add_edge_attribute((0,1), ('c','z')) gr2 = deepcopy(gr) gr3 = deepcopy(gr) gr3.del_edge((0,1)) gr3.add_edge((0,1)) gr4 = deepcopy(gr) gr4.del_edge((0,1)) gr4.add_edge((0,1)) gr4.add_edge_attribute((0,1), ('d','k')) gr5 = deepcopy(gr) gr5.del_node(2) gr5.add_node(2) gr5.add_node_attribute(0, ('d','k')) assert gr == gr2 assert gr2 == gr assert gr != gr3 assert gr3 != gr assert gr != gr4 assert gr4 != gr assert gr != gr5 assert gr5 != gr if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-cycles.py0000644000175000017500000000650411345314436020245 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.algorithms.cycles """ import unittest import pygraph from pygraph.algorithms.cycles import find_cycle from pygraph.algorithms.searching import depth_first_search from pygraph.classes.digraph import digraph from pygraph.classes.graph import graph from sys import getrecursionlimit import testlib def verify_cycle(graph, cycle): for i in range(len(cycle)): assert graph.has_edge((cycle[i],cycle[(i+1)%len(cycle)])) class test_find_cycle(unittest.TestCase): # Graph def test_find_cycle_on_graph(self): gr = testlib.new_graph() cycle = find_cycle(gr) verify_cycle(gr, cycle) def test_find_cycle_on_graph_withot_cycles(self): gr = testlib.new_graph() st, pre, post = depth_first_search(gr) gr = graph() gr.add_spanning_tree(st) assert find_cycle(gr) == [] # Digraph def test_find_cycle_on_digraph(self): gr = testlib.new_digraph() cycle = find_cycle(gr) verify_cycle(gr, cycle) def test_find_cycle_on_digraph_without_cycles(self): gr = testlib.new_digraph() st, pre, post = depth_first_search(gr) gr = digraph() gr.add_spanning_tree(st) assert find_cycle(gr) == [] def test_find_small_cycle_on_digraph(self): gr = digraph() gr.add_nodes([1, 2, 3, 4, 5]) gr.add_edge((1, 2)) gr.add_edge((2, 3)) gr.add_edge((2, 4)) gr.add_edge((4, 5)) gr.add_edge((2, 1)) # Cycle: 1-2 assert find_cycle(gr) == [1,2] def test_find_cycle_on_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,20001)) for i in range(0,20000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() find_cycle(gr) assert getrecursionlimit() == recursionlimit # Regression def test_regression1(self): G = digraph() G.add_nodes([1, 2, 3, 4, 5]) G.add_edge((1, 2)) G.add_edge((2, 3)) G.add_edge((2, 4)) G.add_edge((4, 5)) G.add_edge((3, 5)) G.add_edge((3, 1)) assert find_cycle(G) == [1, 2, 3] if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-critical.py0000644000175000017500000000577211300062627020554 0ustar morphmorph# Copyright (c) Pedro Matiello # Tomaz Kovacic # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for pygraph.algorithms.critical """ import unittest from pygraph.algorithms.critical import critical_path from pygraph.algorithms.critical import transitive_edges,_intersection from pygraph.classes.digraph import digraph def generate_test_graph(): ''' Generates & returns a weighted digraph with one transitive edge and no cycles. ''' G = digraph() G.add_nodes([1,2,3,4,5,6]) G.add_edge((1,2), 1) G.add_edge((2,4), 4) G.add_edge((1,3), 1)#transitive edge G.add_edge((2,3), 20) G.add_edge((3,5), 3) G.add_edge((4,6), 5) G.add_edge((5,6), 4) return G class test_critical_path_and_transitive_edges(unittest.TestCase): # critical path algorithm def test_critical_path_with_cycle(self): G = generate_test_graph() G.add_edge((5,2),3)#add cycle assert critical_path(G) == [] def test_critical_path(self): G = generate_test_graph() assert critical_path(G) == [1,2,3,5,6] # transitive edge detection algorithm def test_transitivity_with_cycle(self): G = generate_test_graph() G.add_edge((5,2),3)#add cycle assert transitive_edges(G) == [] def test_transitivity(self): G = generate_test_graph() G.add_edge((2,5),1)#add another transitive edge assert transitive_edges(G) == [(1,3),(2,5)] # intersection testing (used internally) def test_partial_intersection(self): list1 = [1,2,3,4] list2 = [3,4,5,6] assert _intersection(list1, list2) == [3,4] def test_empty_intersection(self): list1 = [1,2,3,4] list2 = [5,6] assert _intersection(list1, list2) == [] if __name__ == "__main__": unittest.main()python-graph-1.8.2/tests/unittests-accessibility.py0000644000175000017500000002470711346044014021610 0ustar morphmorph# Copyright (c) Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Unittests for graph.algorithms.accessibility """ import unittest import pygraph from pygraph.algorithms.searching import depth_first_search from pygraph.algorithms.accessibility import accessibility from pygraph.algorithms.accessibility import mutual_accessibility from pygraph.algorithms.accessibility import connected_components from pygraph.algorithms.accessibility import cut_nodes from pygraph.algorithms.accessibility import cut_edges from pygraph.classes.hypergraph import hypergraph from copy import deepcopy from sys import getrecursionlimit import testlib def number_of_connected_components(cc): n = 0 for each in cc: if cc[each] > n: n = cc[each] return n class test_accessibility(unittest.TestCase): def setUp(self): pass def test_accessibility_in_graph(self): gr = testlib.new_graph() gr.add_nodes(['a','b','c']) gr.add_edge(('a','b')) gr.add_edge(('a','c')) ac = accessibility(gr) for n in gr: for m in gr: if (m in ac[n]): assert m in depth_first_search(gr, n)[0] assert n in depth_first_search(gr, m)[0] else: assert m not in depth_first_search(gr, n)[0] def test_accessibility_in_digraph(self): gr = testlib.new_digraph() gr.add_nodes(['a','b','c']) gr.add_edge(('a','b')) gr.add_edge(('a','c')) ac = accessibility(gr) for n in gr: for m in gr: if (m in ac[n]): assert m in depth_first_search(gr, n)[0] else: assert m not in depth_first_search(gr, n)[0] def test_accessibility_on_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,2001)) for i in range(0,2000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() accessibility(gr) assert getrecursionlimit() == recursionlimit def test_mutual_accessibility_in_graph(self): gr = testlib.new_graph() gr.add_nodes(['a','b','c']) gr.add_edge(('a','b')) gr.add_edge(('a','c')) ma = mutual_accessibility(gr) for n in gr: for m in gr: if (m in ma[n]): assert m in depth_first_search(gr, n)[0] assert n in depth_first_search(gr, m)[0] else: assert m not in depth_first_search(gr, n)[0] or n not in depth_first_search(gr, m)[0] def test_mutual_accessibility_on_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,5001)) for i in range(0,5000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() mutual_accessibility(gr) assert getrecursionlimit() == recursionlimit def test_mutual_accessibility_in_digraph(self): gr = testlib.new_digraph() gr.add_nodes(['a','b','c']) gr.add_edge(('a','b')) gr.add_edge(('b','a')) gr.add_edge(('a','c')) ma = mutual_accessibility(gr) for n in gr: for m in gr: if (m in ma[n]): assert m in depth_first_search(gr, n)[0] assert n in depth_first_search(gr, m)[0] else: assert m not in depth_first_search(gr, n)[0] or n not in depth_first_search(gr, m)[0] def test_connected_components_in_graph(self): gr = testlib.new_graph() gr.add_nodes(['a','b','c']) gr.add_edge(('a','b')) cc = connected_components(gr) for n in gr: for m in gr: if (cc[n] == cc[m]): assert m in depth_first_search(gr, n)[0] else: assert m not in depth_first_search(gr, n)[0] def test_connected_components_on_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,5001)) for i in range(0,5000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() connected_components(gr) assert getrecursionlimit() == recursionlimit def test_cut_nodes_in_graph(self): gr = testlib.new_graph() gr.add_nodes(['x','y']) gr.add_edge(('x','y')) gr.add_edge(('x',0)) gr_copy = deepcopy(gr) cn = cut_nodes(gr) for each in cn: before = number_of_connected_components(connected_components(gr)) gr.del_node(each) number_of_connected_components(connected_components(gr)) > before gr = gr_copy def test_cut_nodes_on_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,5001)) for i in range(0,5000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() cut_nodes(gr) assert getrecursionlimit() == recursionlimit def test_cut_edges_in_graph(self): gr = testlib.new_graph() gr.add_nodes(['x','y']) gr.add_edge(('x','y')) gr.add_edge(('x',0)) gr_copy = deepcopy(gr) ce = cut_edges(gr) for each in ce: before = number_of_connected_components(connected_components(gr)) gr.del_edge(each) number_of_connected_components(connected_components(gr)) > before gr = gr_copy def test_cut_edges_on_very_deep_graph(self): gr = pygraph.classes.graph.graph() gr.add_nodes(range(0,5001)) for i in range(0,5000): gr.add_edge((i,i+1)) recursionlimit = getrecursionlimit() cut_edges(gr) assert getrecursionlimit() == recursionlimit def test_accessibility_hypergraph(self): gr = hypergraph() # Add some nodes / edges gr.add_nodes(range(8)) gr.add_hyperedges(['a', 'b', 'c']) # Connect the 9 nodes with three size-3 hyperedges for node_set in [['a',0,1,2], ['b',2,3,4], ['c',5,6,7]]: for node in node_set[1:]: gr.link(node, node_set[0]) access = accessibility(gr) assert 8 == len(access) for i in range(5): assert set(access[i]) == set(range(5)) for i in range(5,8): assert set(access[i]) == set(range(5,8)) def test_connected_components_hypergraph(self): gr = hypergraph() # Add some nodes / edges gr.add_nodes(range(9)) gr.add_hyperedges(['a', 'b', 'c']) # Connect the 9 nodes with three size-3 hyperedges for node_set in [['a',0,1,2], ['b',3,4,5], ['c',6,7,8]]: for node in node_set[1:]: gr.link(node, node_set[0]) cc = connected_components(gr) assert 3 == len(set(cc.values())) assert cc[0] == cc[1] and cc[1] == cc[2] assert cc[3] == cc[4] and cc[4] == cc[5] assert cc[6] == cc[7] and cc[7] == cc[8] # Do it again with two components and more than one edge for each gr = hypergraph() gr.add_nodes(range(9)) gr.add_hyperedges(['a', 'b', 'c', 'd']) for node_set in [['a',0,1,2], ['b',2,3,4], ['c',5,6,7], ['d',6,7,8]]: for node in node_set[1:]: gr.link(node, node_set[0]) cc = connected_components(gr) assert 2 == len(set(cc.values())) for i in [0,1,2,3]: assert cc[i] == cc[i+1] for i in [5,6,7]: assert cc[i] == cc[i+1] assert cc[4] != cc[5] def test_cut_nodes_in_hypergraph(self): gr = hypergraph() # Add some nodes / edges gr.add_nodes(range(9)) gr.add_hyperedges(['a', 'b', 'c']) # Connect the 9 nodes with three size-3 hyperedges for node_set in [['a',0,1,2], ['b',3,4,5], ['c',6,7,8]]: for node in node_set[1:]: gr.link(node, node_set[0]) # Connect the groups gr.add_hyperedges(['l1','l2']) gr.link(0, 'l1') gr.link(3, 'l1') gr.link(5, 'l2') gr.link(8, 'l2') cn = cut_nodes(gr); assert 0 in cn assert 3 in cn assert 5 in cn assert 8 in cn assert len(cn) == 4 def test_cut_edges_in_hypergraph(self): gr = hypergraph() # Add some nodes / edges gr.add_nodes(range(9)) gr.add_hyperedges(['a1', 'b1', 'c1']) gr.add_hyperedges(['a2', 'b2', 'c2']) # Connect the 9 nodes with three size-3 hyperedges for node_set in [['a1',0,1,2], ['b1',3,4,5], ['c1',6,7,8], ['a2',0,1,2], ['b2',3,4,5], ['c2',6,7,8]]: for node in node_set[1:]: gr.link(node, node_set[0]) # Connect the groups gr.add_hyperedges(['l1','l2']) gr.link(0, 'l1') gr.link(3, 'l1') gr.link(5, 'l2') gr.link(8, 'l2') ce = cut_edges(gr) assert 'l1' in ce assert 'l2' in ce assert len(ce) == 2 if __name__ == "__main__": unittest.main() python-graph-1.8.2/tests/testrunner.py0000644000175000017500000000470311305051056017123 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. import sys sys.path.append('..') import pygraph import unittest import testlib import logging from os import listdir log = logging.getLogger(__name__) def test_modules(): modlist = [] for each in listdir('.'): if (each[0:9] == "unittests" and each[-3:] == ".py"): modlist.append(each[0:-3]) return modlist def run_tests(): for each_size in testlib.sizes: print ("Testing with %s graphs" % each_size) suite = unittest.TestSuite() testlib.use_size = each_size for each_module in test_modules(): try: suite.addTests(unittest.TestLoader().loadTestsFromName(each_module)) except ImportError as ie: log.exception(ie) continue tr = unittest.TextTestRunner(verbosity=2) result = tr.run(suite) del suite def main(): try: rseed = sys.argv[1] testlib.random_seed = int(rseed) except: pass print ("") print ("--------------------------------------------------") print ("python-graph unit-tests") print ("Random seed: %s" % testlib.random_seed) print ("--------------------------------------------------") print ("") run_tests() if __name__ == "__main__": main() python-graph-1.8.2/tests/testlib.py0000644000175000017500000000441111451445012016355 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Helper functions for unit-tests. """ # Imports from pygraph.algorithms.generators import generate, generate_hypergraph from random import seed from time import time from sys import argv # Configuration random_seed = int(time()) num_nodes = { 'small': 10, 'medium': 25, 'sparse': 40 } num_edges = { 'small': 18, 'medium': 120, 'sparse': 200 } sizes = ['small', 'medium', 'sparse'] use_size = 'medium' # Init try: if (argv[0] != 'testrunner.py'): print print ("Random seed: %s" % random_seed) except: pass def new_graph(wt_range=(1, 1)): seed(random_seed) return generate(num_nodes[use_size], num_edges[use_size], directed=False, weight_range=wt_range) def new_digraph(wt_range=(1, 1)): seed(random_seed) return generate(num_nodes[use_size], num_edges[use_size], directed=True, weight_range=wt_range) def new_hypergraph(): seed(random_seed) return generate_hypergraph(num_nodes[use_size], num_edges[use_size]) def new_uniform_hypergraph(_r): seed(random_seed) return generate_hypergraph(num_nodes[use_size], num_edges[use_size], r = _r) python-graph-1.8.2/tests/test_data.py0000644000175000017500000000403511276032451016665 0ustar morphmorph""" Misc functions used for testing, including the generation of test-data. """ EDGES = [ ("China", "Russia"), ("Afghanistan", "Iran"), ("China", "Russia"), ("China", "Mongolia"), ("Mongolia", "Russia"), ("Mongolia", "China"), ("Nepal", "China"), ("India", "Pakistan"), ("India", "Nepal"), ("Afghanistan", "Pakistan"), ("North Korea", "China"), ("Romania", "Bulgaria"), ("Romania", "Moldova"), ("Romania", "Ukraine"), ("Romania", "Hungary"), ("North Korea", "South Korea"), ("Portugal", "Spain"), ("Spain","France"), ("France","Belgium"), ("France","Germany"), ("France","Italy",), ("Belgium","Netherlands"), ("Germany","Belgium"), ("Germany","Netherlands"), ("Germany","Denmark"), ("Germany","Luxembourg"), ("Germany","Czech Republic"), ("Belgium","Luxembourg"), ("France","Luxembourg"), ("England","Wales"), ("England","Scotland"), ("England","France"), ("Scotland","Wales"), ("Scotland","Ireland"), ("England","Ireland"), ("Switzerland","Austria"), ("Switzerland","Germany"), ("Switzerland","France"), ("Switzerland","Italy"), ("Austria","Germany"), ("Austria","Italy"), ("Austria","Czech Republic"), ("Austria","Slovakia"), ("Austria","Hungary"), ("Austria","Slovenia"), ("Denmark","Germany"), ("Poland","Czech Republic"), ("Poland","Slovakia"), ("Poland","Germany"), ("Poland","Russia"), ("Poland","Ukraine"), ("Poland","Belarus"), ("Poland","Lithuania"), ("Czech Republic","Slovakia"), ("Czech Republic","Germany"), ("Slovakia","Hungary")] def nations_of_the_world( G ): """ This is intended to simplify the unit-tests. Given a graph add the nations of the world to it. """ for a,b in EDGES: for n in [a,b,]: if not n in G.nodes(): G.add_node(n) if (not G.has_edge((a,b))): G.add_edge( (a,b) ) return G python-graph-1.8.2/tests/__init__.py0000644000175000017500000000000011242053103016426 0ustar morphmorphpython-graph-1.8.2/README0000644000175000017500000000570611663035302014065 0ustar morphmorphpython-graph A library for working with graphs in Python -------------------------------------------------------------------------------- SUMMARY python-graph is a library for working with graphs in Python. This software provides ο»Ώa suitable data structure for representing graphs and a whole set of important algorithms. INSTALLING To install the core module, run: make install-core To install the dot language support, run: make install-dot Alternatively, if you don't have make, you can install the modules by running: ./setup.py install inside the module directory. DOCUMENTATION To generate the API documentation for this package, run: make docs You'll need epydoc installed in your system. WEBSITE The latest version of this package can be found at: http://code.google.com/p/python-graph/ Please report bugs at: http://code.google.com/p/python-graph/issues/list PROJECT COMMITTERS Pedro Matiello * Project maintainer/leader; * Graph, Digraph and Hipergraph classes; * Accessibility algorithms; * Cut-node and cut-edge detection; * Cycle detection; * Depth-first and Breadth-first searching; * Minimal Spanning Tree (Prim's algorithm); * Random graph generation; * Topological sorting; * Traversals; * XML reading/writing; * Refactoring. Christian Muise * Project commiter; * Dot file reading/writing; * Hypergraph class; * Refactoring. Salim Fadhley * Project commiter; * Porting of Roy Smith's A* implementation to python-graph; * Edmond Chow's heuristic for A*; * Refactoring. Tomaz Kovacic * Project commiter; * Transitive edge detection; * Critical path algorithm; * Bellman-Ford algorithm; * Logo design. CONTRIBUTORS Eugen Zagorodniy * Mutual Accessibility (Tarjan's Algorithm). Johannes Reinhardt * Maximum-flow algorithm; * Gomory-Hu cut-tree algorithm; * Refactoring. Juarez Bochi * Pagerank algorithm. Nathan Davis * Faster node insertion. Paul Harrison * Mutual Accessibility (Tarjan's Algorithm). Peter Sagerson * Performance improvements on shortest path algorithm. Rhys Ulerich * Dijkstra's Shortest path algorithm. Roy Smith * Heuristic Searching (A* algorithm). Zsolt Haraszti * Weighted random generated graphs. Anand Jeyahar * Edge deletion on hypergraphs (bug fix). Emanuele Zattin * Hyperedge relinking (bug fix). Jonathan Sternberg * Graph comparison (bug fix); * Proper isolation of attribute lists (bug fix). Daniel Merritt * Fixed reading of XML-stored graphs with edge attributes. LICENSE This software is provided under the MIT license. See accompanying COPYING file for details. python-graph-1.8.2/misc/0000755000175000017500000000000012012025435014123 5ustar morphmorphpython-graph-1.8.2/misc/logo.txt0000644000175000017500000000051511300623125015624 0ustar morphmorphLICENCE The image is provided under Creative Commons Attribution-Share Alike 3.0 license. Check http://creativecommons.org/licenses/by-sa/3.0/ for more information. ATTRIBUTION: The artwork for the official logo of python-graph was designed by TomaΕΎ Kovačič . python-graph-1.8.2/misc/logo.png0000644000175000017500000005334111300577763015616 0ustar morphmorph‰PNG  IHDRΞ|oρΗ- pHYs  šœ OiCCPPhotoshop ICC profilexڝSgTSι=χήτBKˆ€”KoR RB‹€‘&*! Jˆ!‘ΩQΑEEΘ ˆŽŽ€ŒQ, Š Ψδ!’Žƒ£ˆŠΚϋα{£kΦΌχζΝώ΅Χ>η¬σ³Οΐ –H3Q5€ ©BΰƒΗΔΖαδ.@ $p³d!sύ#ψ~<<+"ΐΎxΣ ΐM›ΐ0‡κB™\€„ΐt‘8K€@zŽB¦@F€˜&S `ΛcbγP-`'ζΣ€ψ™{[”! ‘ eˆDh;¬ΟVŠEX0fKΔ9Ψ-0IWfH°·ΐΞ ² 0Qˆ…){`Θ##x„™FςW<ρ+η*x™²<Ή$9E[-qWW.(ΞI+6aaš@.Βy™24ΰσΜ ‘ΰƒσύxΞΞΞ6ŽΆ_-κΏ"bbγώεΟ«p@αt~Ρώ,/³€;€mώ’%ξh^  uχ‹f²@΅ ιΪWσpψ~<ί5°j>{‘-¨]cφK'Xtΐβχς»oΑΤ(€hƒαΟwο?ύG %€fI’q^D$.TΚ³?ΗD *°AτΑ,ΐΑάΑ ό`6„B$ΔΒBB d€r`)¬‚B(†Ν°*`/Τ@4ΐQh†“p.ΒUΈ=pϊažΑ(Ό AΘa!ڈbŠX#Ž™…ψ!ΑH‹$ ɈQ"K‘5H1RŠT UHς=r9‡\FΊ‘;Θ2‚ό†ΌG1”²Q=Τ ΅CΉ¨7„F’ Πdt1š ›Πr΄=Œ6‘ηΠ«hڏ>CΗ0ΐθ3Δl0.ΖΓB±8, “cΛ±"¬ «Ζ°V¬»‰υcΟ±wEΐ 6wB aAHXLXNΨH¨ $4Ϊ 7 „QΒ'"“¨K΄&ΊωΔb21‡XH,#֏/{ˆCΔ7$‰C2'ΉI±€TFnR#ι,©›4H#“ΙΪdk²9”, +Θ…δδΓδ3δδ!ς[ b@q€ψSβ(RΚjJεε4εe˜2AU£šRέ¨‘T5ZB­‘ΆR―Q‡¨4uš9ΝƒIK₯­’•Σhhχi―θtΊέ•N—ΠWΛιGθ—θτw †ƒΗˆg(›gw―˜L¦Σ‹ΗT071λ˜η™™oUX*Ά*|‘Κ •J•&•*/T©ͺ¦ͺήͺ UσUΛT©^S}FU3Sγ© Τ–«UͺPλSSg©;¨‡ͺg¨oT?€~Yύ‰YΓLΓOC€Q ±_γΌΖ c³x,!k «†u5Δ&±ΝΩ|v*»˜ύ»‹=ͺ©‘9C3J3W³Rσ”f?γ˜qψœtN η(§—σ~Šήο)β)¦4LΉ1e\kͺ–—–X«H«Q«Gλ½6ν§¦½E»YϋAΗJ'\'GgΞηSΩSέ§ §M=:υ.ͺk₯‘»DwΏn§ξ˜žΎ^€žLo§ήy½ηϊ}/ύTύmϊ§υG X³ $Ϋ Ξ<Ε5qo</ΗΫρQC]Γ@C₯a•a—α„‘ΉΡ<£ΥFFŒiΖ\γ$γmΖmΖ£&&!&KMκMξšRMΉ¦)¦;L;LΗΝΜΝ’ΝΦ™5›=1Χ2η›η›Χ›ί·`ZxZ,Ά¨ΆΈeI²δZ¦YξΆΌn…Z9Y₯XUZ]³F­­%Φ»­»§§ΉN“N«žΦgΓ°ρΆΙΆ©·°εΨΫΆmΆ}agbg·ΕΓξ“½“}Ί}ύ= ‡Ω«Z~s΄r:V:ޚΜξ?}Ετ–ι/gXΟΟΨ3γΆΛ)ΔiS›ΣGggΉsƒσˆ‹‰K‚Λ.—>.›ΖέΘ½δJtυq]αzυ›³›Βν¨Ϋ―ξ6ξiξ‡άŸΜ4Ÿ)žY3sΠΓΘCΰQεΡ? Ÿ•0kί¬~OCOg΅η#/c/‘W­Χ°·₯wͺχaο>φ>rŸγ>γ<7ή2ήY_Μ7ΐ·Θ·ΛOΓož_…ίC#dzΡ§€%g‰A[ϋψz|!ΏŽ?:Ϋeφ²ΩνAŒ ΉAA‚­‚εΑ­!hΘ쐭!χη˜Ξ‘Ξi…P~θΦΠaζa‹Γ~ '…‡…W†?ŽpˆXΡ1—5wΡάCsίDϊD–Dή›g1O9―-J5*>ͺ.j<Ϊ7Ί4Ί?Ζ.fYΜΥXXIlK9.*6nlΎίόνσ‡ββ γ{˜/Θ]py‘ΞΒτ…§©.,:–@LˆN8”πA*¨Œ%ςw%Ž yΒΒg"/Ρ6шΨC\*NςH*Mz’μ‘Ό5y$Ε3₯,εΉ„'©ΌL Lέ›:žšv m2=:½1ƒ’‘qBͺ!M“ΆgκgζfvΛ¬e…²ώΕn‹·/•Ιk³¬Y- ΆB¦θTZ(Χ*²geWfΏΝ‰Κ9–«ž+ΝνΜ³Κې7œοŸνΒα’Ά₯†KW-X潬j9²‰ŠΫ—Ψ(άxε‡oΚΏ™ά”΄©«ΔΉdΟffιζή-ž[–ͺ—ζ—n ΩΪ΄ ίV΄νυφEΫ/—Ν(Ϋ»ƒΆCΉ£Ώ<ΈΌe§ΙΞΝ;?T€TτTϊT6ξέ΅aΧψnΡξ{Όφ4μΥΫ[Όχύ>ΙΎΫUUMΥfΥeϋIϋ³χ?‰ͺιψ–ϋm]­NmqνΗύ#ΆΧΉΤΥ=TRΦ+λGΗΎώοw- 6 UœΖβ#pDyδιχ ίχ :ΪvŒ{¬αΣvg/jBšςšF›Sšϋ[b[ΊOΜ>ΡΦκήzόGΫœ499β?rύιό§CΟdΟ&žώ’ώΛ/~ψΥλΧΞјё—ς—“Ώm|₯ύκΐλ―ΫΖΒΖΎΙx31^τVϋνΑwάwο£ίOδ| (hω±υSΠ§ϋ“““˜σόc3-Ϋ cHRMz%€ƒω€ιu0κ`:˜o’_ΕFL IDATxΪμ½g˜Χu&|Ξ½:§ιΙ3`ƒœ3‚I0IE*0(Y²ΌφΪ’eΛ’ƒμ]ΦΪk}^Λλ•,}’₯•¬`%J€(1η"‰Dœ€Ιy:§ χήοGuΒτΜ`@b@¨—ΟΓ§ΡSέ]]]υΦΉο9η=(„6lΨ°1— φ!°aΓ† ›jmΨ°aΓ¦Z6lΨ°aS­ 6lΨTkΓ† 6ΥΪ°aΓ† ›jmΨ°aΓ¦Z6lΨ°aS­ 6lΨTkΓ† 6ΥΪ°aΓ† CΊΚΏΏ`Ή@ Ϊ§„ 6lͺ½”$+8/Yν "hΣ­ 6lͺ½$$Λη\X¬Šˆˆ „@Blž΅aΓ†M΅oŒqΣd…θU#YJ&γΊΙQ"H)‘Ϊq 6lͺ½3 H¬0‘4οΟι™8ˆ€FγY@t©RΘ­6„\+ζ…V΅TΥ\²dgmΨ°ρf€W5Έa°\Ξ@Μ«ˆ¨ΘD7Ψλ=‘Ÿξ:ύςΙaΓ4%J )( œ ΁ A nYTϋρλΪ7.¬v*’}ήΨ°aΓ¦Ϊ©y6“Υ€D‚(Kd0’ώΪΗ½ί!‡LaF §3Ν07-ͺύ³χ­Z9/DlUΑ† 6Υ–ƒsžLjœ B(!T"OύΥ’©œG•σAμΜG AΘh&γβ wϊΨu‹[O°aΓ†M΅E€RZN3(!ˆ@Κέέ9όg?y"ͺΉ¨ο&ɜ~χ¦ϋαυΆ˜`Γ†Ωΰέ—Y-!„”`Gτο|]"δby%t©ΏΦύίΎ?«3ϋ²aΓ†M΅ΝκŒq‹h b<­Σ#Gš‘P3Κ3ˆ± ΰV~σZΟ·ž:ΞΈ=rΨ† W7Υr.4Ν „!"“lΨ°qSmΞBp!€1~Ό?Κ…ΐ{"bcΡbΫ|wCι―…¨ΧbaΜσr‰m ύεξ³Yέ΄O&6l\TΛ7Mn…΄ DV7z"™b£"H„PD@‘ α@XΞͺ.F(=ΐ²Γ&Sr¬/?‘ΆO&6lL‡wsY(η‚1&@!§™ΓΙ\‘%%J( 8Zχ°j „ @Q h""0ΞA%˜Θš§cνυ~ϋ|²aΓΖUΥZŽ΄άϊ?ΣδΊΙ± Θ”PŠQ¦D&(I(”(< „"PDŠ@%‚H ‚P"HςςHOΔΈ]υeΓ†«0ͺ΅”VΑ… –-PD$J2…RΘ ’`Y 8@„ΰˆ(@ ΰ±΄Θϋ/bN˜@Η2L(„°MmΨ°qQ-₯„"9η%~§ά ͺE΅m‚@…8Q@„°h˜žΒβRΖ…fXD †ΙAδGηX… 6lΨ°qUP-!(ΛDΣ@pŽͺ"5xo@œ‚`œ«2•aΕαbΗ €VΕ‚Λζc\ωΒ!D>FΖY,λ«WQΨ\kΓ†«ƒj@UεdR8ͺDΪΒnμ4GS6"?Η Φ;ΦSV΄k±°(Π±ΘS2 ’n p€Ί€Λr·ΘڎjmΨ°qUQ­„ΔcA,mψT)­™B@·#δsΫT{9 Λ΄ΊΪ;4γŠœfΆΤωβ¦%_{ρτ`2'!γNΗ»Η’aŸ£ΉΚΣXεφ;E’Αΰ<žΦGف‰τP4“ΥMY"Q3…*K_Ήg}c•Ϋ0˜e±H)R;‡cΓΖΫ„Α±˜Ι&Ο jo½2ΥWΛB―Χ‘iξH$-(€œf,žWυ™kΝΏωΝA‘x(p"#b4ž‰eœAU¦²D@qΣδ&– ‚ΥcΖ€4W;ϊ½+–Ο« –7ό!Λ²­\‘”ς¨φq°qΙΡΥ7šΥ'ϋτ·5V_ ϋv |•$*¬rYD@0LvΈσlj¨Λα«Go5JaŒΠ|ξ’sžΣ8X^‹”H4& d“‘Φ΄­œ_₯ι&"ΰpΘ’=|z$sΖήΞ‘O RΔqίFϋ€ΨΈδθ―t}j_–{W ΥζrΖψxΚrβB8ΚρΣρΒ>Β…ν7ΩF§dΙϊ₯hΑ¦V°|·˜ €ΤCTːψ/žΩ}ϋ†EυΥ~Σdΐ(΅γΩiρȁžΌΠ9Λ0.–4μbc.pnp’ςΙu‹η] ϋvUDaBˆ±±€a2@²LΣν?žή#Έ@$H$nδγݟ\[σχοYyη’Ί5uΎ¦€3μUƒ.₯Ϊλh{o«ώ½Ν ͺYDNφ͐y5ΑDVϋΏΎΚ˜@D«°!›5„]: N Ε"i«NV)lΨΈtHητΑρΨ€'«ƒ^σŠP«Š¨6Λ€R9Bˆe^@)yrορ#=RΑ'άbλEwl[ξPε-!έ䩬›Œs!KΔνT\ͺμυ¨υnώί~ψH}•ίηr,¨―zdΟΡχl^±aY‹n˜ˆh¦¦‡έH:¨έAgcŽI€γιμ€'7Χ*ςΑrοώ¨VΧΝ±ρT>ΌPιLοΨO^~ΪΊΈ.UωψΞM²,%Sša2J θuԅ܍aoMΠνR%!x*­mZήzΝ’§FtΖΒ>·Η₯|γΧ/&Σ9‚ΘΉr9ƒ1nŸτ6l\~ ΗΗ’ΙIOΆ5UΛWΖ*κ]Υ cγ)Γ`%@uέψΟηφ₯²ZYHΛ?ΎmύΒ–ΪlVG΁ ŒAΎ[©0PŒ1‡CώέΫΆύαΏύt4’¬xÁ#έ}ο>ϊ‘›Φ Ζΐ4Y.gΈέWhz}<‘Œ¦ƒ αR₯† «1t™κ ­Κό9χDνXZλOΕΊ¨υ;ηΧxς›Ό&£‰l2kC {5~§SyK—%γ’o<5Οf ¦J€Κλh­υ]’ˆ>§CγρH"Hη½T(%α€§&θ ϋ=—Šͺ†#‰X2cύ³>μ_R7ωЧ©μD"ΚhΕ'e‰ϊάʐ·.δ{‹Wλΰx,’HG“™bΘβu9ͺƒž–Ίͺ Ύ|$’Θj“Λ«ƒΕΗρTv8‰$‹oπΊΒώΪ·ΆΫ6Υ$Ωx,Cˆ5E~fίΙݝg%$ˆ L.ΥΧΌοΪU¦Υ%fsqΛ ΡάΘ ’¦™­MΥχmίπ³—xœͺC‘ͺύήο>ΆkΫͺ…uU>Γδ„@.g(Š$ΛoÍΤ`όΑ½g‹%ίΏq~qάΩΡžΘ“―χν™87–4Μόy6/μYήΊkΣόΥσ'ŸΗΟ8tvάͺ[£οά8Ώ­φΒ§γk§F_>9d=φ8δΦZ_Η@L7ι.ε+zΗR_ύνε/t©·΄Φϊ3A4σΐξ3Gz&Ί†βΦWπ:ε%Αλ–Υί½iΎ4λrζTΞxϊώƒgΖΊ†β‘t1a]t5…άλΫͺοΨΠφ:f8Θν=Χ7‘_'ύΑ-ΛΌΙθρC½Ο8=‰η—±AΊ¬)xλšζ[V7½ιŸ΅w8ςΤΎγ:zz†#£ΡDy†έηv4UΧ.žχΑk[«χŸμ~vΙςΧ[<οΦΝΛ‹dύΰ ‡zG"ΕΏzœκ};7V½‡:{υΒ‘Žžαήα ³@C;7.ύκΘz<8Ϋ{μ܁Žžsƒγ‘DzΚζΧΖκΰŠΦ†;·―ž. Υ;ωεσu³4[:ΰq}ꎭEާ²Oν;ΎηΨΩsƒγcΡd:§—Φ݈ιί΄aΙ{Άœα@uMn^ ˆ ›ͺΰΘ遧_;~δτ@ίH$ZΈ—X7‰ωυU›–ΝΏχ¦σκB6ΥΎYκ1ΨθX"ίπ (ςΐHτ§/ε₯ƒόœ€OξΌΖοqf¬–qE‘‚!7cœ3!„ ‰DNΑηw^»ζΩ#±ϊΟοvžžψΟ§χ}ώޝˆΐ….2έ?#kΜL&;Ψk5³ΐκ–*‹jΏ|ΗO_9ΚMΎαχާzΗS―œΊ{ΣόίΏeYΉVF3ά{ΆψO‡LπΦε܁Ώ|jιQλqCΠυ-­?}εΤΑu2χ«=gΟ; )Ω±¬aJͺ₯ˆπθΑžo?}bϊ>ΨΡσO?~ͺ«od6OΔΣ_ώή#¦99O°me[ιΞ”Ξ%ΟηSΏΗωοΏΌλΣ•oˆ-υUπΕϋΥ±³ƒ³? ΣYνλ<―HΗnΫ<ιO£dέXόηŸ<=ιφ08Oν;>4ϋΧ?Ή·Κ?Yψts’↔Ιiύ­_—‡±Σa8’ψΫοώφkzοκφ¦9Ί<ί΅i±tZ‹DR„ e{¨ΘkΗΊ_8ή%!ADd‚ΧψΌχμX`œq—[υx¦X<†‚n‰.ΈΰB7Μν«Ϋ7΄Ν‰%.U&ˆί{|w:«[ςƒNk—€Li°L&6ΩΣEžUezν’Ί{ΆΆέ΅iώš ΕΰωcίΎ£œ¦w,k(ώσΤpόd\¦ΓρΎΘX’”έΉ²)g0>»ς7Ν`S.‰’—O}»ΐ”ΰ†ΆκΛÚ?3ρύη:fψˆο?ί1‰gΫλύΎ¦υ‹wώ«οέΦΦXuήΥϋΛ=gΏσΜΙiŽsιͺΙμ«Ώ}£Θ³™nYT{έ²ϊΚIυ/Ÿz`χ™Yώ”Oμ9φ'η³δΩ<ιg΄άωRNUnm —ρŽ>)tOΙ³–Bjαΐ›‚πψξžαΙ%½#ΡΚΫΙ,yΆτCŸψן?[yΆΔΣΩS}£•Qlx6υ'3_{ΰΉL™vaG΅³ΘN0>4gLHB(²‰§όβ>ΖΈ΅ ¦ί±Ή±.˜ΙθςLΩ.­(’ίοŸHIM“»Κ'oΩϊ§ίωe*£©2υΉ―u{ωPΧm[WhΊ†Α2έsyΫO‘<«σδαΎ}§ς'ί­kš?yΓβƐΛͺiMkζι‘ψ7Ÿ<~€§t=όδ•SΪͺ7·Χδ—Ζk›Άλ΄ΕM†ΙχtŽ4%ŽυFŠφ²ΝaΟ’Ζ€ΑψΟ?Ώ³ -t=v°ΧzΌΈ!πε{7œcm`Šε:g|ύ±£9ƒQ‚½ύφ΅σκN‰’ŒfžI|χΩ“‡Ξ–ΦŒξ=ϋžυσ¦Τ”_<>XΞ›™ώρ{Vμ\Υδ/‹Σ?qύ’‡φϋΡ‹]FA¬όΡ‹]K;–7Lz7Qvΐ?Τϋς‰!p*§nX|ΣΚΖ*Ÿƒ"ftσx_δΫOŸμ,έ’~ϊΚι›V5]PθxτΥ#_ώή£†Ι*΄x^ݍ―hmLg΅ݏ½z4==5΄7Χ”gΜNυ^xaD‰εTπZΙ’†p ψW·Smk¬ή±nΡΒ¦šζš a²Γ]}Ω=τΟ?yϊPgoεφΏxv$ͺνš˜αΫέ°~ρw¬»vυBλŸ]}#_ύΙΣ―θάrίρ³sD΅οB!•ΚMDRVαpHGΊϊ;tŒ±Š 8―Γρρ7)2eœ Œq§CΜnPJ‚A7 ZcmΰΧ©ςy™œ΅<Ž'xα ζ?L“§RΪΫ~4n^ΥτG·­˜Z!u)yךE ₯°επΉρ"·ͺ2½vi©Φ§wƒδϊρ˜fLώ +ZΎωΕϋ?°cέ$ίΈ­ _ύ쇦[γ·Τ…ŠΫ η¦'£΅‹šΏώ…ϋξχήwσΖ₯—ΞΏaύβMΛςE·l^ώΝ/άΝ/~δKŸΈ}JߏKύΒύ7WΦKFYM/_ΰOG΅ŠDΏpΝ_ύά‡Š6–°ξ`B€ͺJ§ΊGή:E$ˆύQ‚χοΨθv)ša"η\Q₯pxΆiVE‘ηωή0‡"}β¦Ν„ Ιͺ”ξι8χςλ§$JB€¦ιτΫ##H”T.δ+αuΘΫ—–B’tΞ(η¦kΚhb,™;tnŠΨ‘s0vv$Q\M—3Λ[„C¦εL:%Τ–d_ΞEδ|ΡζπΉρbΥA•Χ±‘mVΦ₯[Χ–«εΙ·Ι"ŒSYz!£²e™:έδΙ¬1•Θ.~σΚλ•KμϋnήΈueΫΜοίΪP-W΄ω«²μw;ΛΧΕ•Lηr(ό‘κ/…ΗΰD<=ι™Ί*ŸKUΚo$•―joωτϋ½ΰ›o[5ΕBd8R’ΪS}£Ή ›Ϊ†p`ζ7χΈΤΚ…¬€Ή Œή=i1!ΔΠP\7˜D©%ͺζΟ^|-™Υ%@ €ˆηοYΉlν’ζlΦ@.@pWy/*yεχ;“©œ¦™” ¦›ΛΪξάΈκΑ=―;d $Jώο»Φ.jx]V~,™Μ9²tΩ±½Ny6-^°°ή/Qb]Š)Ν8;š\1/T”zΏσΜ‰XZ‡BB%χνι)ΦΜ {V·T]ͺ―@} ηW{‹Υ»\ˆdΆ€2.ŠχXά¨ς8fσΉ-aO}Π]|m±+dŠ›B«ΌxΟ¦²……Αψ”+ƒH"ύμώΙΕjυa‡o\Α½5ƒŠ’Ίš ·ΆͺτλOΔ+ ο–΄ΤέΌiΩE„2š‘Hgœ‹&»‡&RYmp,I¦…€Jq θu+ŠTΌW$εβ};7Ί^MΩΗ•,λ ‰$τ ϋΖ ‹gžsΓςΛΪσΧ4s6ηέC΅ιxΧςεωαΞήƒ½;zwυΞ)4δsΛ4^drzGΟπ€ ښͺoXΏx6o5₯ ’ΗYβ莞αΚ#°ͺνS23Eρ{뜍lx—ΊnŽŒΔ‹Χ§’HύΓΡv$ ABˆεhpοΆ υΥ~]7AΞ…$‘šο› Ϋαv+Φ]QΧΝΊj½Ϋ7˜œ !™’‡φ>Υ3*KΤς^H¦΄ΛŸ›ύB¨6ΰTΚ8h4vή2φΦΥ₯μχXςτω!ήΉ‘Δ™αψ”Κιe[ΝL{V˜|¨μ»ΤΜϊžJ –ίNϊ'RsύSμ;~v3²D―]έ6›w?;8^n,W-Ξ£Œή ‘V–θlϊPŸά{όsϋηψΟ?ωξo^9ΤΩ;{Gζ–ΊP‘κS9mx"^±‡αYNWΤτ)Φεϊuθ­zKΤΟόΆη¦:n³Ή·]ΥT;4Λζ $(ΐςκΏzιΠD*-Q*Q$77·ΞΏvνΒ¬fXΦŒρPΘγtΎ™"„«Ό”!@Πuσ† ‹WΟo²n­1£?{~Ώn˜yϋΖ‰¬ΈRΓeJΚG’MΊΣ/ŸZX—?­ “—gΐ c0-ˆΡΦ΄ΧœοΕΉ(_­«£α”‡’—!±YYcδχ8—-h˜%ΥN:³aACUΉ:QΉ~_:ΏΎ&8Sus"ϋοίωνίόϋΓϋŽŸ›αΜ•%ZY!€σΚ恟ꩬ^‘¦„XΡƒC•χ9ϋΙ.™IB‚Δδά£¨χέΈMƒε iJUΥ›wŸSU)t1Ζ„a2·Cω[H|eJ_8ΪυΪρY–¬ 5“Ρ―„2Ϋ7'ΊU©ΌΐφΥΞα\‘ψ‰qqθlι|έ±ΌώŠbωVv¦ό₯sΝ΄ΙLr€vΘηnž]„UY†€νM₯:ί‘ρx2« Ϊ™˜n8’ψόΧxdΧ•ώΛ„ΰΒ¦šλτΦMrΟMλ3Όqύ’Ι ŒΟSWVbΙmkœ-©UφψΊT₯HεcΡd$‘ΠOjΤΑ…€Σνsͺ"-n£_ω―Υjš90\€„ *ςΘxβ—―$’$Iηέ²n~cU:£#"@„Ί:ί[œΊΈ’Ιœ¦™„bN3–·5άΆnΩ£ϋΚ„"%ψƒgv―lkp9“1! Ο:Κ8κ1«3VF'ΑŠΊ·Νν5μ>cEˆ}γ©#έ›Ϊk`"™;\ΘΞάΚ,σϋ—‘jQ¦€Ψh›Φ.BΓ)7B ϋsΊŸ}£ΡΚ o6­ΥŒΚ:§¦Ϊ`°,¦§*»Κ;n'!žΞώΕ7~uδτ@εŸvn\zΧυk6Υ”Ϋk½zδtε}’6XΪ``lrΤ©Htζ Άr8Ω3ι‡*seΡd¦rψΒόΊͺ™}™)Z*«ƒ^χ\ύΦοψ¨vp(–Ιθ”"ˆ|JδΧ―Όή:dI‘€d™Ή’±αΆk–“ρPΠSiίu± ”TUyAB β·―« x™ε‚δτπθc―•d« 5͌Η3—hf #i½p©#BuΕ‘YΥR΅Έ¬©¬hJ{zΈδΝΊ¬)Tp]Qη†"‘¦²ΔΰplΆΩ-έdεΉΑ†ΰά~/‰LQΏο›έ5?0­Μώ·7ΥPRΊ΄;z†υ *_ΡΦ8]Έχ­‡^ͺδΩ–Ίͺο~ιγ_ωΓ»―]΅°œg5έ¬΄ώ ϊ\εζ[‡:ϋ&mΰq9Κγξpμμ`ΟΘDεΞνΞ Ž•ϋ”[Έ ωμh$OM>–Ν―Ÿ»AdοlͺΕ2γcΙόΤq!TU>άΡϋbG§ƒJŠ,I”Μ”‘άwύ‡C6tUͺ­½4νLΓγV9γ@ΧΝ¦Ίΰ½Χn(Έ$€μ:x¦wLQ$A$’ΉΛ–c\³›ΎΣ3ž,jŠDλ*œ_(Α Kλžkϋύ§Ηн©½Z•―¬ωŒ%ε©°ξΡdVg³yαp,[ήΛΫRν½ό;Ÿ] ~²{(šš|nͺ –swe”Λ‘„ΌSί?vτ<όλ•QκΏ|ξC—ΞŸͺqK―΄›)jι\ͺΒ+Ά©&Hgη'ωςαΚ΄XyΪπD’Rβ(߁ιD‰Κ[T]•O’suΏƒ©Φ0X_¬Τ“Υƒϋΐ+9.UQ(αœηLγΦUΛ–/lΘd΄Ό )DuοRΉΐ B8μ₯α\p! ƒνX·hYs b,›}ΰΕƒ†Α!ΐΕ2—'?–Κ½c³JŸθ‹3?.Uš²ΑμΦ5ΝE&¦΄}QΨΥ‘―ΰ yΧ.©ΏΞ™’r3Γ“ΡΡΩ­*Ξ 'ΚC๞¦>eΩ|₯@9eτύΤΎ•rjy›¬5)g i¨φωƒ•νŸύЎ…Σ‘gΗ'©ˆ°h^Iρμ‰TΪh<³ZSŽΗRΟΌv²R|(0Ζϋ*rb5AίΜ?ˆ$2•…Ζ‹[κζ.Ωπ¦Ϊ‘‘D:­†Ω "KOν;qz|Μ­*Š,B2ΊQησΏoΫ*#o‡*η^―£κ’ΤRU)ts&,φχΊŸΌq3—)„>{€γΐ‰Y¦Φ@tϊ2εǚΩQζΰ7ΓfΌ•/–›§κk Ή7€ΨŒfv D‡c™bθ·΄)Π4c oωY}9Sgk”ΆjζKΗ/l&"<{΄Ώx†½ŽbCǜ RεΝ·4zfΧ‚"žΪ{|χΡ)«X‘κ@‰ιϊF£M―Έ‘Dfsd~ρ܁sclnέ²’©01,«•ul~·sfΙUθκ\η«ΚRC•ξ~εw*Υ&“Ή‘ΡxΎκ@€Σ‘tž~μυ£NYv;’D5Γ08»gλΊpΘ£λ& p₯uu~ΌΤΧz ΰr:eΞΈ%]­Zά|ΫΪe¦ΘΗψΓgχ¦%DˆX;0VyΆŒE;+Θnφ?χΣ§φM>‘ιΓ7+^ΑιœΦ]QήΠ\ yέ3Š3ϊT±°Χη™Γ9UοHͺε\τχGLƒ[φ]T’šn<ΈϋυŒϋ]NE–„ρ\nγό–-+[³YCŒσpΨ3γlσω1!ηξΎvmΨηΞΟ@<54ςμk'¬>ΕB~,{ΤρΎθ‡ϋfΨ –Φώκ™r—€›VMKš›ΫkŠΆΦηFOξ΅^θqΘ[] D¦‘l%Miƒ‘Λ” yΤΛK—ύH<ϋΝ'g²ύO振=v΄˜DrΘτ¦•dξγπ5νSάα~ώμώύ'»§άώ΅έ_ψ·_Nι•Uφϋ=²υ{΄2'6ΐ8―¬…PdiΚ6Ÿx:ϋυ_>WYΫPεσ”―ί§ `³šρΓΗχΞ €=3πεο=Z©<άΎeΕβ²9Ύc±ΚmζΥ†fξKΚjΖh$YAΠ‘š€χͺ£Z!c\ΧMΛ‡PΣL³Μ(hx8‹g­~MΑ…ͺHΟΏΦq »'θvΉ*AŒ§³nY½ηϊυ²L­qΖΉΗ­ΦΤΜΥb―Χαυ:ΟΆ-UΊf ω›9EςσW GUE²z‚‰l2™‹Η³ccΙα‘Δπp|l,¦S)MΧΝKU3o0ώυǏΎrrκUs"£ν/φ— Έ{Σό†ΕάκΦB3ΨΉ‘δΉΡόΙΊcyCθBΎhεL$s―v ]Άsι[ZλΛJ9ΠσέgON9‰'•3Ύϊ›7Κ'SάΈ²qσ’šΛ°“οέΆrΚεόŸγΑ'φ+¦Θ„€ρXκΏzαOώυη㱩…ψΟνTε˜ΞεP¦«τš’ϋφŸμ” z†'ώς›U–aΑω]™œ>έ Κ'φύχ‡_όD.Δ#§Ώτ­_ŽO–ΏΤ‡πΧ—ΜVNΙE„†κΐΜG;–ΚtO~a8ΰQ•9,~½‚κjM“iš™Λι΄–ΝΊfš&cL•ˆD‰,S·G•%:8³ξZB§CιιpλE y=2%‘T:™ΛύΞ΅[4†Sωl @]NkZΓΥήtZ³ Ώ έΌiΓ’ηt‘HβX"υ«—ζƒΧ#€@dœŽ–­Τςaˆ„’"SU•NEUίόD!£™ώ£½ΏύζΥM­΅ωec"£λ‹όΗ G{JΧαβ†ΐ]Σ;ΓZ'ρ5‹j=Πc0^€*BpNJ 75-j8Ι²gδBόψεSn‡Όf~•"ьfj&+7u½δνŸή±κ―ώ³C}﹎αXζƒ[Z[k}™@,­νόπΕc½₯XεώτKΘe‘–Χ,l^έήτΖ©Ι:i,™ω·~½~IΛΊΕσͺ|ξΞή‘ηvTV)w¨ηΥχyΚB}ŸΫYš:ζ(©¬1Σ>υωϋn²J}Ο Œν9zφοžŽλ­yΰΖbΙ‘i¦?ίώυK#‘ΔoX7―6δs;βιlgΟΘ#»ήx|Ο±JΝΑηv|ιwnŸ΄η§ϋΗ*n$jλ…:ΎϊF"•ίx!‚~ΗS-η"‘ΜΖ’™x"«εLΣd\°UDΓd @€ˆDӈH- IΤδμW»§4m^MΘι5݌$ΣΛλλwnZšΝΦdrΖxu΅ΧοŸΫκHU‘‚AχΨX’R’Μλv|μ†MΟΟ P"δ‰ΓΗ·­h]·΄%§Φ¬Δ·΄׊Σ5ΝΤ43ΦœNΕγQ•7u³­ 8Χ΅†-§˜Ώ|κρΓ}­5ή°Ο©l$žιŒ— ¦·ϊΕχ―_Θ€j]kxA·«ΜaAw6,YλwnYTσΒ±Α’†π•‡7]ŠL3šΩ\εωζΉvξ~šλ—ΥώΞeώLIϊ|μ`ο«Γ j|΅'γ’"=iδm]ΐυε{6Μ―η­ΓγR?wΟMφ΅¦€Ρƒ=;zfy-X9η•>/!ŸkΊN ΧU[嫌C_<Τy¦tΩ‚†¬¦wυVœs” 4‹¦*ƒΣrόϊ₯ΓΟμh© …|ξ‰xΊsͺ`pͺς—>qϋ¦eσ'KdΓœŠ<ݍ€ˆ3½yŠDgί(όΞ£ZΞΕψxrd$‘LζγοB$Rπη%B‚V£WΙ½Χ鐟ίίΉο\wίγw;β`< €χ_·ΡεPR r.TUͺ―\†θ$t'S9k"Ί¦›λ–ΞΫΉrΙΣGNΘH1φΓgχ.n©Sd‰ !I”β·)εκΈΞ p.i-—3Ό^‡ΗγΈΨύw*go[Ρ;–:Ϊ±–νΣ™R‡<κ—οΫΈryvCή°°¦œj·.ͺ ΝΞUύ£ΫΫwwŽ”§ι£yΕΆ>8η½ŸΊq1"όπΕΞbim,­>7΅m[οo>Έnξν)±~ρΌΟ~θ†―ώτι)έU¦Œ@ύη$£XŸΗYήΞ›3ΜJZ ϋ=ΣuRΌ[7/?>Υ4ςΎΡhίht6;VU–”‹$TΓβ©μ”iε’Θίώξ•#Ώ8•ΚFΐλΊ`|ZΩΚμT•ono«o›V;I=ΦίΩ9f@’(₯„PbΥDE’‡μtΚ.‡βr(ͺb1“5ύ[!TU‹?Έο°[Uͺͺ"%³Ϊx*}ϋΚ₯KΪκ3Y-‹Cυυ·²Ώˆ—DͺΓ^DΰBp.β‡[τΈ8δϋǎχ =σΪI—SVdšΞκgc―|ϊPοΊŸ8Ψ³ηδpχP<«²L$‚ΐ"άx<¦/VΐΥLτ¨ψΡMwnœ?ƒyΰŽε φ{ΧnœuOm{½―Hϊ‡|ΑE¬˜ϊΛ»ΦLι?MiΕŠ\Y—Α”Φ“Χ‘εΒ«fL[ΫπΙσ'™ω›†<κ=[ΫώΟ§ΆΞΐ³ε{5₯Οχ$°σ8sϊκ‹ίΈώξž•m>€›–ΝΚή½jaSeX:Ώlω|Έ«·’Έ—΄ΜΎ½ΊΥεcΈfβ‚[WΆUv΅-,ψ oT”Žy\κE^·¦ύ_ΈΚъΗΞ&+š#Ϊfρζ•ζ>^·£ά η]՚&λιˆq!ςΒ‚Ae‰R‰ι¬>Νδ4Σδ\p \ΕοQ=NE‘)cά09₯δ‘=GFSΙ₯Mun—#§ιƒ±F_ΰ½[Wcœ#"3y0δ~+Ά2½τ¨^―3Ο‰θ†ΩXυαkΦη™W)Hο94―ΎΊ7ͺνι™JjqΝ΄ψΐ§J~η––ΠΦE΅υa39€ιŒ&„έkωXνsώυΦή΄²ρ₯γƒΗϋ’ύ©΄fΚi­ρ­k oZX³qa΅D/βŽ{¬7ZdΆ₯MΑ₯ϊ½gέΌ–jο/χœy£{b(𱄋φ:ί†…5εΫ[$B.8ŸΖ₯Jε£Ξgn7ΨΠV½ͺ%΄»sdί©ΡSCρ3Γρ¬Ξ$JjΞφ:ΊΦπκωη΅ Ož_Χ~CAžvΝβ^p•οαΚ­Σ·­j[ΡΪπόΑŽέGΞtτ —’^—caSυŠΦΖυKZYΩJ ωʏžœτςΕσjέefΫ£‘depfσ*ΏΫωχΏώ―ό艙KΝ6/_π‰Ϋ―YΠPυ»πΓΔω^6ΕOδœWΖΤu!?όΑϋw½qϊ'Oν›a†.\»jαΫWοά΄t:Ή|<ž¬μ©» 5—PΉWΥΟ”…Ζ—x™ύR)νΤ©αxqbΠ0™εΡνVOυMg$š6 †s9cσŠω›V¬|=&U™i0!‚n΅΅ΖWrϊœŠ"QŠ(„08KeΝ±Dφτpb4ž£»z’λχ¬¨ 8 ƒ!b"™SUIQήŽ83’ψΕξRθ·,Έ„³ml\ŽΨ[1Έαšε­ε~Zo;z†#•5[σλ«ΞŸμ2]±‰Dφdǐn0Y’ € αP%JΙϋ»ŸHdcŒ›L!œŠδuJU^§Ο©¨ ‘€&ηιœIk‰Œ–ΜšΊΙ(γ’DΉβν7Τ‘αρ\*σΡ­›[«R©X“q)ij )o“ΧT,–6t“b…ν]½‘ζ’TΣ έ!Σ5Ν‘Υ^E¦B“s#' Yj©φ6„ά=c©c½Ρ¬atާώΟ3'κ½+*ε\K$²απεφšΚhζϋλΓ‰‚΅ΰ²¦ΰυΛlΚ{[ ›μ;Ώ’9ΏKŠ ήύ"ΔΉ@eΡ«,Ρφ暫σW»T«ιfΧ©-gJ2±tI—CΞιζƒ{Ξξ‹ζ„ΙγγˆPγw.¬σ6UynE‘%ΙκS\pΖEVgcράΩ‘xοX*©™ T’LO]ƒΗ·}]»Œs‚(ŠκΫ΄<ΜεŒρ‰”U9«Κh$ύ]gΖΣ7™ί%―n Wy%4Έ°Š¬• ’5ΪWPΔϊ Ϋ©H‡Ξ§²ΖΑΑψΓΊοΫΆPιŒξΥΜΛωνrϋ—ίΎQμw ?²}α\;ؘZ:ΰβkΏxnW…χΦ•mSvχΎ878™jYΊ$³ΠmͺBˆ3gF‰¬Ο U‘t“ύηΎsGS†ΠMΖΉaАG]ΧZΥRνu*Τδ`2žΜθ–ΐk ‚D±!θjΉ&šrΗϊ"§†ΐ„DIR <tπ}›ζK&a\ ‚‘³ώώh{{ !—;Χ‰€M“K”X Ώ>Ψ3˜€q—*/m ʍg„5FΕΊ[ϊ’€…[D]•ι’zί‰ώhΞΰΊ¦­zA½_7˜ΰ"Φ.ΥFSΪ?ζη•*―[Zύr;€½”μωΏ~ςT,™ΉyΣ²›6,™aΛtVϋΪΟ?π܁IΟ«²tΟΞ ³τ}9Q9¦W•₯–Z[@˜ŒŽ&G†VFRPŠˆπ³=玦tž3LΖpYs`Νό*—*λŒeRLX - ˜ΟŽYώƒP"#§"m^XSνuξ?3j˜ Πψmo,μΌfEc2₯ˆD±X6Ί¬κ•a°D2‹@–igοΔΎ(rA6WΉ…ΐHR³Ύa‘e r΄Θk–.Ξ™ŠL«}΁‰tΪ`ϞϊtΟ ³YsΧ\K₯šΑ^;=ϊ΅ΗŽφ—ψΈ•?½c啬§γΉƒ?f?<»δφ5νw_Ώvω‚ŸΫQή#I€_=rϊgΟμŸrΜψ½;7l_έ~E}©h2SΩuΦΪVικό•ηφkkšΩΧ7!„°ό[ΑεTΩwξPJcΉΌ©ΚšUKƒγ‘”&„ΰBˆβ$AΪh…~„ ˆ±!δZყ'˜i"ΒΓ§ΗΤϊB>§n0‚h >6– ]xR³YέΠ™Ε•¦Ι_θ՘!Ό.E’ΟhŒ .„%(zΒZD°ώ³ŽΡME"ŠDϋz£wΕ³!―ΓRl ΓT/TΤςV0Ο~ε‘Γ{»Ξ›λR₯ΏωΰΊ+m°Ν;YΝψΩΣ―YMΖ_8ΨωΒΑΞΖκΐωυ-u‘Ί*"λθθι™Ϊγυ¦ KώψΓ7β–‘‰$*»'ζΊωυκ₯Ϊ±±D"™“δ|ɁۑtυLΌ2ž\p.–4[kΌρŒnζ#=Α,’‚Ύ<ΙZm+Δ΄f\j[½―s &L>aπNί·}‘n0@&’YM3ŽKFIV,Κy>.BX7ŒB˜ ρx– A’H<ϋΖHΉŠDši2‹gV~°πΖeβ[A±&χŒ€΅ξ‘DΨοΰŒsM›[ͺΝjζ€ΎUE’_Έsυφ₯υ6?^ʐφΐΙ£g&·₯ŒΕΖb³yω{·ό³ϋo–%z₯}―Σύ£©άdΕΩOΙ΅©φ"`š|ΤςΩA.Δ³§Η3Œs“3!jύΞ–jO’P …Ετδ\ !‚qΰb4g¦2Ί*SfςBZ’ΛBΈŠEͺ-xΖAbΝί%₯g Ÿ…Xϊ\Λj°XE „ΜΗΚ‚ ΐΟfυxV/Κ&·Τ…σJ»ŠΚΑyœi Bƒ\^6QUδ·0χσW·T­™_e³αε!άΖκΐ-›—™ŒkΊa˜¬άL–¨$Q‡,ΡwHαA\Ώ€ΕώY/զӚUσdQ‹$ΣΡ‘XΜΘ§(Μ¦fr!Λ ΄ΐσ™y°4ΐ’z€ωβΪB4* j&‚Δ’^-©"Ε„ΙD(ΰΠuΟ‹9K!g‘Ι-M–1ΞΈ`ά΄dYΖcά0™ΙΉi0έ4M“›ŒŒ›ŒΣMf˜¦f2έ45ΓΤMΣϊ“nš:γ†iŒλ̜ ~’ψpQ`WQ`©P¦•‚VφŒW• ‚5R2Χ•h·έ^ώ ’Ι©ΪΗΑ¦ΪΩ ΅Ίi–FΖ"ΒH"Η)†Α`Η@$›΄:.LYP΄­…²ycSΘt[£oω’ϊd*…°¦ΰpVŒ…±(I ”ke±3LΡ'XΪY«Ά"―;c^Λ°RbHΡR> ›3v¬nξŽf^LΰΕ·ΊsBj\ςέήζq*YΝ\¨ͺt™m!mΨ°qεR-!θχ»(%Ε:]77,¨:ˆS"L’Λ#άIΡξT| D‘2ΉfI]4–1M^²H8οMσ*C‘hEΉ A±4­XζPxŠD”@‚”B€”PJAB %H%B ‘”d³ϊΨX ˜LΒ>²­-ϋbΧΎ±τE±-'€Α£όΡΆΦ†jo6gX;{e™Ϊ' 6Υζασ9œ%Ρ(E@Π s^}`}pόεLΏΰΛΛΉυ‚©(§*έΡ^νq©ΙtΞ² ΰ&ΟsjΡ© ΤΤ –φJ,-ήD*QJ₯(IΤ’QJσ|Šˆ’D‘δ…$$?NΌ’›s‘ΣŒx,+ID7ΈͺΠO]ΧάίύTO @η3‹ ‚ 'Έ‘ΖϋρΝ κͺά™¬ŒσͺΗο·½bmΨxη…sχξgύ93*Μ4™κ&ϋΦ³L°¬~ΙΎ"qΘ·ΥxήMk"•+ZgόNΥ![Ή,J •ˆDK$‰y“‚ΒωΌoΩ¬ήujDΧMI’BU–ΕΓ§Fλ=›Μq!€Lσ!6’eρΠμQnk―ΉvYƒ,M3g<p55…μ!΅6lΨT;™Œ~ψpO&£K2!„Χγ8ΣωΡρα˜ΞΉa^’₯ͺΌ- ~xk›a˜–ί c<φ.]RφΪs$“ΉΣgFM“Yσ~Ρᐳ9γhχψ‘ώxZ›ΘšΑ9""ͺ«ΪδUΧ4Φ,ϋ½ŽœfZn`ŒqŸίΩά’$»Χ† ›j§Bo_€³c¨θ"„πϋGOόβΤDΒδL{KφΥD¦”ν!Η]›0Ζ “#γάαW―jv:ίώ©v©Tξ\χx6£KΝ“¨ͺH†Ι’=šΘ&²†ΞΈC–ά)μsϊ<ͺ,S]7­οb• ‡ΓήΊZ΅ΗyΩ°aSνtB?>08/KζΏίyόΜΨCccB0ΝμΒY²σߐ"QeΑΫ}ΫW5ιΊiΝcœB–-­‡―ΧdM3£i!₯ωή^JΠΚ§!–ŒΈ°ζAδ[’…‡\[λ ν’6lͺ½r9γψρH$-•& —K™ˆeŸ:6p,ΓrŒ3έ&\H(TB\κ’o^R;Ώ!Νζl,?…φφΪΖΖΰ•v £ΡτΘH"Φ8„K.΅ώZ彈 ¨R0ΰͺ²KhmΨ°©vΦH&sGφ§RZ1ΆB8’¬HotξˆžΣ˜Ζ›ω)cεsdσ΅ ‘ˆ,ΔB—΄Ή1°²­š’ΞθV’Θdœ²°­¦©)xekΖx*₯E’ιt*g˜œ³ΌSd±Ά—TΙνVύ>§Η£Ϊ$kΓ†M΅x<{ςδ`"‘³J¦,Ά₯NΕ0Yχ@μΨP’'™›0…AΠh r‚(#(œ‡i‘W]Ϊΰom R‚™œΑ˜°JnM“9r{{mmοΚ?θ†ΙtέΤ53§™†a‚Bˆ$§Sq»J©νo`Γ†M΅o™Œ~κΤΘΘHΒ*ώ/>O* ₯”θ‹$²c±l,™Υ80§DT™zJίιu+N‡b¦n0Ξ…5…Α²― {ΪZ«=Ϋΐ† W=ΥZ‹θžή‰Ύήˆ›€θBPpi‘$"ΛΤΚY~.…»Β09cάdœ ζ- Έ.§άΤj¨Ψ z6lΨT{i­―?::Χ4ΚΗd!L2/·G@ω‘ œ’Σ©ΤΤxƒ+ ¨Λ† 68ͺ΅LζFFγcI+/_`yFs. ’ͺJ―#t…Γ^—Λ&Y6lΨT; hš™Jεβ‰l*™Σ4SΣLΓ`±†‡ƒ$Q‡CφyΑ ΫγQNΕξO΅aΓ†M΅oŒqΖΈa0‹pηBI’²DUUr8δbι‚ 6lΨTkΓ† 6Ξƒ΅·aΓ† ›jmΨ°aΓ¦Z6lΨ°aS­ 6lΨTkΓ† 6ΥΪ°aΓ† ›jmΨ°aΓ¦Z6lΨ°aS­ 6lΨTkΓ† οόΕ„ς¦ОFIENDB`‚python-graph-1.8.2/misc/epydoc.css0000644000175000017500000003712211174204747016142 0ustar morphmorph /* Epydoc CSS Stylesheet * * This stylesheet can be used to customize the appearance of epydoc's * HTML output. * */ /* Default Colors & Styles * - Set the default foreground & background color with 'body'; and * link colors with 'a:link' and 'a:visited'. * - Use bold for decision list terms. * - The heading styles defined here are used for headings *within* * docstring descriptions. All headings used by epydoc itself use * either class='epydoc' or class='toc' (CSS styles for both * defined below). */ body { background: #ffffff; color: #000000; } p { margin-top: 0.5em; margin-bottom: 0.5em; } a:link { color: #3f3eb0; } a:visited { color: #3e75b0; } dt { font-weight: bold; } h1 { font-size: +140%; font-weight: bold; } h2 { font-size: +125%; font-style: italic; font-weight: bold; } h3 { font-size: +110%; font-weight: normal; } code { font-size: 100%; } /* N.B.: class, not pseudoclass */ a.link { font-family: monospace; } /* Page Header & Footer * - The standard page header consists of a navigation bar (with * pointers to standard pages such as 'home' and 'trees'); a * breadcrumbs list, which can be used to navigate to containing * classes or modules; options links, to show/hide private * variables and to show/hide frames; and a page title (using *

). The page title may be followed by a link to the * corresponding source code (using 'span.codelink'). * - The footer consists of a navigation bar, a timestamp, and a * pointer to epydoc's homepage. */ h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; } h2.epydoc { font-size: +130%; font-weight: bold; } h3.epydoc { font-size: +115%; font-weight: bold; margin-top: 0.2em; } td h3.epydoc { font-size: +115%; font-weight: bold; margin-bottom: 0; } table.navbar { background: #d5dce3; color: #000000; border: 0px groove #c0d0d0; } table.navbar table { color: #000000; } th.navbar-select { background: #3e75b0; color: #d5dce3; } table.navbar a { text-decoration: none; } table.navbar a:link { color: #3e75b0; } table.navbar a:visited { color: #3e75b0; } span.breadcrumbs { font-size: 85%; font-weight: bold; } span.options { font-size: 70%; } span.codelink { font-size: 85%; } td.footer { font-size: 85%; } /* Table Headers * - Each summary table and details section begins with a 'header' * row. This row contains a section title (marked by * 'span.table-header') as well as a show/hide private link * (marked by 'span.options', defined above). * - Summary tables that contain user-defined groups mark those * groups using 'group header' rows. */ td.table-header { background: #d5dce3; color: #000000; border: 1px solid #608090; } td.table-header table { color: #000000; } td.table-header table a:link { color: #0000ff; } td.table-header table a:visited { color: #204080; } span.table-header { font-size: 120%; font-weight: bold; } th.group-header { background: #c0e0f8; color: #000000; text-align: left; font-style: italic; font-size: 115%; border: 1px solid #608090; } /* Summary Tables (functions, variables, etc) * - Each object is described by a single row of the table with * two cells. The left cell gives the object's type, and is * marked with 'code.summary-type'. The right cell gives the * object's name and a summary description. * - CSS styles for the table's header and group headers are * defined above, under 'Table Headers' */ table.summary { border-collapse: collapse; background: #ffffff; color: #000000; border: 1px solid #608090; margin-bottom: 0.5em; } td.summary { border: 1px solid #608090; } code.summary-type { font-size: 85%; } table.summary a:link { color: #3f3eb0; } table.summary a:visited { color: #3e75b0; } /* Details Tables (functions, variables, etc) * - Each object is described in its own div. * - A single-row summary table w/ table-header is used as * a header for each details section (CSS style for table-header * is defined above, under 'Table Headers'). */ table.details { border-collapse: collapse; background: #fafafa; color: #000000; border: 1px solid #cccccc; margin: .2em 0 0 0; } table.details table { color: #000000; } table.details a:link { color: #3f3eb0; } table.details a:visited { color: #3e75b0; } /* Fields */ dl.fields { margin-left: 2em; margin-top: 1em; margin-bottom: 1em; } dl.fields dd ul { margin-left: 0em; padding-left: 0em; } dl.fields dd ul li ul { margin-left: 2em; padding-left: 0em; } div.fields { margin-left: 2em; } div.fields p { margin-bottom: 0.5em; } /* Index tables (identifier index, term index, etc) * - link-index is used for indices containing lists of links * (namely, the identifier index & term index). * - index-where is used in link indices for the text indicating * the container/source for each link. * - metadata-index is used for indices containing metadata * extracted from fields (namely, the bug index & todo index). */ table.link-index { border-collapse: collapse; background: #fafafa; color: #000000; border: 1px solid #cccccc; } td.link-index { border-width: 0px; } table.link-index a:link { color: #3f3eb0; } table.link-index a:visited { color: #3e75b0; } span.index-where { font-size: 70%; } table.metadata-index { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin: .2em 0 0 0; } td.metadata-index { border-width: 1px; border-style: solid; } table.metadata-index a:link { color: #0000ff; } table.metadata-index a:visited { color: #204080; } /* Function signatures * - sig* is used for the signature in the details section. * - .summary-sig* is used for the signature in the summary * table, and when listing property accessor functions. * */ .sig-name { color: #006080; } .sig-arg { color: #008060; } .sig-default { color: #602000; } .summary-sig { font-family: monospace; } .summary-sig-name { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:link { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:visited { color: #006080; font-weight: bold; } .summary-sig-arg { color: #006040; } .summary-sig-default { color: #501800; } /* Subclass list */ ul.subclass-list { display: inline; } ul.subclass-list li { display: inline; } /* To render variables, classes etc. like functions */ table.summary .summary-name { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:link { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:visited { color: #006080; font-weight: bold; font-family: monospace; } /* Variable values * - In the 'variable details' sections, each varaible's value is * listed in a 'pre.variable' box. The width of this box is * restricted to 80 chars; if the value's repr is longer than * this it will be wrapped, using a backslash marked with * class 'variable-linewrap'. If the value's repr is longer * than 3 lines, the rest will be ellided; and an ellipsis * marker ('...' marked with 'variable-ellipsis') will be used. * - If the value is a string, its quote marks will be marked * with 'variable-quote'. * - If the variable is a regexp, it is syntax-highlighted using * the re* CSS classes. */ pre.variable { padding: .5em; margin: 0; background: #dce4ec; color: #000000; border: 1px solid #708890; } .variable-linewrap { color: #604000; font-weight: bold; } .variable-ellipsis { color: #604000; font-weight: bold; } .variable-quote { color: #604000; font-weight: bold; } .variable-group { color: #008000; font-weight: bold; } .variable-op { color: #604000; font-weight: bold; } .variable-string { color: #006030; } .variable-unknown { color: #a00000; font-weight: bold; } .re { color: #000000; } .re-char { color: #006030; } .re-op { color: #600000; } .re-group { color: #003060; } .re-ref { color: #404040; } /* Base tree * - Used by class pages to display the base class hierarchy. */ pre.base-tree { font-size: 80%; margin: 0; } /* Frames-based table of contents headers * - Consists of two frames: one for selecting modules; and * the other listing the contents of the selected module. * - h1.toc is used for each frame's heading * - h2.toc is used for subheadings within each frame. */ h1.toc { text-align: center; font-size: 105%; margin: 0; font-weight: bold; padding: 0; } h2.toc { font-size: 100%; font-weight: bold; margin: 0.5em 0 0 -0.3em; } /* Syntax Highlighting for Source Code * - doctest examples are displayed in a 'pre.py-doctest' block. * If the example is in a details table entry, then it will use * the colors specified by the 'table pre.py-doctest' line. * - Source code listings are displayed in a 'pre.py-src' block. * Each line is marked with 'span.py-line' (used to draw a line * down the left margin, separating the code from the line * numbers). Line numbers are displayed with 'span.py-lineno'. * The expand/collapse block toggle button is displayed with * 'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not * modify the font size of the text.) * - If a source code page is opened with an anchor, then the * corresponding code block will be highlighted. The code * block's header is highlighted with 'py-highlight-hdr'; and * the code block's body is highlighted with 'py-highlight'. * - The remaining py-* classes are used to perform syntax * highlighting (py-string for string literals, py-name for names, * etc.) */ pre.py-doctest { padding: .5em; margin: 1em; background: #fafafa; color: #000000; border: 1px solid #cccccc; } table pre.py-doctest { background: #dce4ec; color: #000000; } pre.py-src { border: 2px solid #000000; background: #f0f0f0; color: #000000; } .py-line { border-left: 2px solid #000000; margin-left: .2em; padding-left: .4em; } .py-lineno { font-style: italic; font-size: 90%; padding-left: .5em; } a.py-toggle { text-decoration: none; } div.py-highlight-hdr { border-top: 2px solid #000000; border-bottom: 2px solid #000000; background: #d8e8e8; } div.py-highlight { border-bottom: 2px solid #000000; background: #d0e0e0; } .py-prompt { color: #005050; font-weight: bold;} .py-more { color: #005050; font-weight: bold;} .py-string { color: #006030; } .py-comment { color: #003060; } .py-keyword { color: #600000; } .py-output { color: #404040; } .py-name { color: #000050; } .py-name:link { color: #000050 !important; } .py-name:visited { color: #000050 !important; } .py-number { color: #005000; } .py-defname { color: #000060; font-weight: bold; } .py-def-name { color: #000060; font-weight: bold; } .py-base-class { color: #000060; } .py-param { color: #000060; } .py-docstring { color: #006030; } .py-decorator { color: #804020; } /* Use this if you don't want links to names underlined: */ /*a.py-name { text-decoration: none; }*/ /* Graphs & Diagrams * - These CSS styles are used for graphs & diagrams generated using * Graphviz dot. 'img.graph-without-title' is used for bare * diagrams (to remove the border created by making the image * clickable). */ img.graph-without-title { border: none; } img.graph-with-title { border: 1px solid #000000; } span.graph-title { font-weight: bold; } span.graph-caption { } /* General-purpose classes * - 'p.indent-wrapped-lines' defines a paragraph whose first line * is not indented, but whose subsequent lines are. * - The 'nomargin-top' class is used to remove the top margin (e.g. * from lists). The 'nomargin' class is used to remove both the * top and bottom margin (but not the left or right margin -- * for lists, that would cause the bullets to disappear.) */ p.indent-wrapped-lines { padding: 0 0 0 7em; text-indent: -7em; margin: 0; } .nomargin-top { margin-top: 0; } .nomargin { margin-top: 0; margin-bottom: 0; } /* HTML Log */ div.log-block { padding: 0; margin: .5em 0 .5em 0; background: #e8f0f8; color: #000000; border: 1px solid #000000; } div.log-error { padding: .1em .3em .1em .3em; margin: 4px; background: #ffb0b0; color: #000000; border: 1px solid #000000; } div.log-warning { padding: .1em .3em .1em .3em; margin: 4px; background: #ffffb0; color: #000000; border: 1px solid #000000; } div.log-info { padding: .1em .3em .1em .3em; margin: 4px; background: #b0ffb0; color: #000000; border: 1px solid #000000; } h2.log-hdr { background: #70b0ff; color: #000000; margin: 0; padding: 0em 0.5em 0em 0.5em; border-bottom: 1px solid #000000; font-size: 110%; } p.log { font-weight: bold; margin: .5em 0 .5em 0; } tr.opt-changed { color: #000000; font-weight: bold; } tr.opt-default { color: #606060; } pre.log { margin: 0; padding: 0; padding-left: 1em; } python-graph-1.8.2/Makefile0000644000175000017500000000437511702362451014650 0ustar morphmorph# python-graph # Makefile # Module directories ------------------------------------------------- CORE_DIR="core/" DOT_DIR="dot/" TESTS_DIR="tests/" DOCS_DIR="docs/" TEMP="temp/" PYTHONPATH="`pwd`/core:`pwd`/dot" # General ------------------------------------------------------------ nothing: sdist: clean sdist-core sdist-dot rm -rf dist mkdir dist cp */dist/* dist # Core --------------------------------------------------------------- install-core: cd ${CORE_DIR} && ./setup.py install sdist-core: clean cd ${CORE_DIR} && ./setup.py sdist # Dot ---------------------------------------------------------------- install-dot: cd ${DOT_DIR} && ./setup.py install sdist-dot: clean cd ${DOT_DIR} && ./setup.py sdist # Docs --------------------------------------------------------------- docs: cleanpyc rm -rf ${DOCS_DIR} ${TEMP} mkdir -p ${TEMP} cp -R ${CORE_DIR}/pygraph ${TEMP} cp -Rn ${DOT_DIR}/pygraph ${TEMP}/pygraph/ epydoc -v --no-frames --no-sourcecode --name="python-graph" \ --url="http://code.google.com/p/python-graph/" \ --inheritance listed --no-private --html \ --graph classtree \ --css misc/epydoc.css -o docs ${TEMP}/pygraph/*.py \ ${TEMP}/pygraph/algorithms/*py \ ${TEMP}/pygraph/algorithms/heuristics/*.py \ ${TEMP}/pygraph/algorithms/filters/* \ ${TEMP}/pygraph/readwrite/* \ ${TEMP}/pygraph/classes/*.py \ ${TEMP}/pygraph/mixins/*.py rm -rf ${TEMP} # Tests -------------------------------------------------------------- test-pre: reset test: test-pre export PYTHONPATH=${PYTHONPATH} && cd ${TESTS_DIR} && python testrunner.py test3: test-pre export PYTHONPATH=${PYTHONPATH} && cd ${TESTS_DIR} && python3 testrunner.py tests: test # Tests -------------------------------------------------------------- console: export PYTHONPATH=${PYTHONPATH} && cd ${TESTS_DIR} && python console3: export PYTHONPATH=${PYTHONPATH} && cd ${TESTS_DIR} && python3 # Cleaning ----------------------------------------------------------- cleanpyc: find . -name *.pyc -exec rm {} \; find . -name __pycache__ -exec rm -rf {} \; clean: cleanpyc rm -rf ${DOCS_DIR} rm -rf */dist rm -rf */build rm -rf */*.egg-info rm -rf dist # Phony rules -------------------------------------------------------- .PHONY: clean cleanpyc docs-core python-graph-1.8.2/dot/0000755000175000017500000000000012012025435013756 5ustar morphmorphpython-graph-1.8.2/dot/setup.py0000755000175000017500000000230612000356031015470 0ustar morphmorph#!/usr/bin/env python # -*- coding: utf-8 -*- import os try: from setuptools import setup, find_packages except ImportError as ie: import distribute_setup distribute_setup.use_setuptools() from setuptools import setup, find_packages # Startup appname = "python-graph-dot" appversion = "1.8.2" setup( name = appname, version = appversion, namespace_packages = ["pygraph"], packages = ["pygraph"] + [ os.path.join("pygraph", a) for a in find_packages("pygraph") ], install_requires = [ 'python-graph-core==%s' % appversion, 'pydot' ], author = "Pedro Matiello", author_email = "pmatiello@gmail.com", description = "DOT support for python-graph", license = "MIT", keywords = "python graphs hypergraphs networks library algorithms", url = "http://code.google.com/p/python-graph/", classifiers = ["License :: OSI Approved :: MIT License","Topic :: Software Development :: Libraries :: Python Modules"], long_description = "python-graph is a library for working with graphs in Python. This software provides a suitable data structure for representing graphs and a whole set of important algorithms.", ) python-graph-1.8.2/dot/pygraph/0000755000175000017500000000000012012025435015430 5ustar morphmorphpython-graph-1.8.2/dot/pygraph/readwrite/0000755000175000017500000000000012012025435017416 5ustar morphmorphpython-graph-1.8.2/dot/pygraph/readwrite/dot.py0000644000175000017500000002145211356653661020604 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Functions for reading and writing graphs in Dot language. @sort: read, read_hypergraph, write, write_hypergraph """ # Imports from pygraph.classes.digraph import digraph from pygraph.classes.exceptions import InvalidGraphType from pygraph.classes.graph import graph from pygraph.classes.hypergraph import hypergraph import pydot # Values colors = ['aquamarine4', 'blue4', 'brown4', 'cornflowerblue', 'cyan4', 'darkgreen', 'darkorange3', 'darkorchid4', 'darkseagreen4', 'darkslategray', 'deeppink4', 'deepskyblue4', 'firebrick3', 'hotpink3', 'indianred3', 'indigo', 'lightblue4', 'lightseagreen', 'lightskyblue4', 'magenta4', 'maroon', 'palevioletred3', 'steelblue', 'violetred3'] def read(string): """ Read a graph from a string in Dot language and return it. Nodes and edges specified in the input will be added to the current graph. @type string: string @param string: Input string in Dot format specifying a graph. @rtype: graph @return: Graph """ dotG = pydot.graph_from_dot_data(string) if (dotG.get_type() == "graph"): G = graph() elif (dotG.get_type() == "digraph"): G = digraph() elif (dotG.get_type() == "hypergraph"): return read_hypergraph(string) else: raise InvalidGraphType # Read nodes... # Note: If the nodes aren't explicitly listed, they need to be for each_node in dotG.get_nodes(): G.add_node(each_node.get_name()) for each_attr_key, each_attr_val in each_node.get_attributes().items(): G.add_node_attribute(each_node.get_name(), (each_attr_key, each_attr_val)) # Read edges... for each_edge in dotG.get_edges(): # Check if the nodes have been added if not G.has_node(each_edge.get_source()): G.add_node(each_edge.get_source()) if not G.has_node(each_edge.get_destination()): G.add_node(each_edge.get_destination()) # See if there's a weight if 'weight' in each_edge.get_attributes().keys(): _wt = each_edge.get_attributes()['weight'] else: _wt = 1 # See if there is a label if 'label' in each_edge.get_attributes().keys(): _label = each_edge.get_attributes()['label'] else: _label = '' G.add_edge((each_edge.get_source(), each_edge.get_destination()), wt = _wt, label = _label) for each_attr_key, each_attr_val in each_edge.get_attributes().items(): if not each_attr_key in ['weight', 'label']: G.add_edge_attribute((each_edge.get_source(), each_edge.get_destination()), \ (each_attr_key, each_attr_val)) return G def write(G, weighted=False): """ Return a string specifying the given graph in Dot language. @type G: graph @param G: Graph. @type weighted: boolean @param weighted: Whether edges should be labelled with their weight. @rtype: string @return: String specifying the graph in Dot Language. """ dotG = pydot.Dot() if not 'name' in dir(G): dotG.set_name('graphname') else: dotG.set_name(G.name) if (isinstance(G, graph)): dotG.set_type('graph') directed = False elif (isinstance(G, digraph)): dotG.set_type('digraph') directed = True elif (isinstance(G, hypergraph)): return write_hypergraph(G) else: raise InvalidGraphType("Expected graph or digraph, got %s" % repr(G) ) for node in G.nodes(): attr_list = {} for attr in G.node_attributes(node): attr_list[str(attr[0])] = str(attr[1]) newNode = pydot.Node(str(node), **attr_list) dotG.add_node(newNode) # Pydot doesn't work properly with the get_edge, so we use # our own set to keep track of what's been added or not. seen_edges = set([]) for edge_from, edge_to in G.edges(): if (str(edge_from) + "-" + str(edge_to)) in seen_edges: continue if (not directed) and (str(edge_to) + "-" + str(edge_from)) in seen_edges: continue attr_list = {} for attr in G.edge_attributes((edge_from, edge_to)): attr_list[str(attr[0])] = str(attr[1]) if str(G.edge_label((edge_from, edge_to))): attr_list['label'] = str(G.edge_label((edge_from, edge_to))) elif weighted: attr_list['label'] = str(G.edge_weight((edge_from, edge_to))) if weighted: attr_list['weight'] = str(G.edge_weight((edge_from, edge_to))) newEdge = pydot.Edge(str(edge_from), str(edge_to), **attr_list) dotG.add_edge(newEdge) seen_edges.add(str(edge_from) + "-" + str(edge_to)) return dotG.to_string() def read_hypergraph(string): """ Read a hypergraph from a string in dot format. Nodes and edges specified in the input will be added to the current hypergraph. @type string: string @param string: Input string in dot format specifying a graph. @rtype: hypergraph @return: Hypergraph """ hgr = hypergraph() dotG = pydot.graph_from_dot_data(string) # Read the hypernode nodes... # Note 1: We need to assume that all of the nodes are listed since we need to know if they # are a hyperedge or a normal node # Note 2: We should read in all of the nodes before putting in the links for each_node in dotG.get_nodes(): if 'hypernode' == each_node.get('hyper_node_type'): hgr.add_node(each_node.get_name()) elif 'hyperedge' == each_node.get('hyper_node_type'): hgr.add_hyperedge(each_node.get_name()) # Now read in the links to connect the hyperedges for each_link in dotG.get_edges(): if hgr.has_node(each_link.get_source()): link_hypernode = each_link.get_source() link_hyperedge = each_link.get_destination() elif hgr.has_node(each_link.get_destination()): link_hypernode = each_link.get_destination() link_hyperedge = each_link.get_source() hgr.link(link_hypernode, link_hyperedge) return hgr def write_hypergraph(hgr, colored = False): """ Return a string specifying the given hypergraph in DOT Language. @type hgr: hypergraph @param hgr: Hypergraph. @type colored: boolean @param colored: Whether hyperedges should be colored. @rtype: string @return: String specifying the hypergraph in DOT Language. """ dotG = pydot.Dot() if not 'name' in dir(hgr): dotG.set_name('hypergraph') else: dotG.set_name(hgr.name) colortable = {} colorcount = 0 # Add all of the nodes first for node in hgr.nodes(): newNode = pydot.Node(str(node), hyper_node_type = 'hypernode') dotG.add_node(newNode) for hyperedge in hgr.hyperedges(): if (colored): colortable[hyperedge] = colors[colorcount % len(colors)] colorcount += 1 newNode = pydot.Node(str(hyperedge), hyper_node_type = 'hyperedge', \ color = str(colortable[hyperedge]), \ shape = 'point') else: newNode = pydot.Node(str(hyperedge), hyper_node_type = 'hyperedge') dotG.add_node(newNode) for link in hgr.links(hyperedge): newEdge = pydot.Edge(str(hyperedge), str(link)) dotG.add_edge(newEdge) return dotG.to_string() python-graph-1.8.2/dot/pygraph/readwrite/__init__.py0000644000175000017500000000006711271421150021532 0ustar morphmorph__import__('pkg_resources').declare_namespace(__name__)python-graph-1.8.2/dot/pygraph/__init__.py0000644000175000017500000000007011242044237017543 0ustar morphmorph__import__('pkg_resources').declare_namespace(__name__) python-graph-1.8.2/dot/distribute_setup.py0000644000175000017500000003673711701075071017753 0ustar morphmorph#!python """Bootstrap distribute installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from distribute_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import os import sys import time import fnmatch import tempfile import tarfile from distutils import log try: from site import USER_SITE except ImportError: USER_SITE = None try: import subprocess def _python_cmd(*args): args = (sys.executable,) + args return subprocess.call(args) == 0 except ImportError: # will be used for python 2.3 def _python_cmd(*args): args = (sys.executable,) + args # quoting arguments if windows if sys.platform == 'win32': def quote(arg): if ' ' in arg: return '"%s"' % arg return arg args = [quote(arg) for arg in args] return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 DEFAULT_VERSION = "0.6.24" DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" SETUPTOOLS_FAKED_VERSION = "0.6c11" SETUPTOOLS_PKG_INFO = """\ Metadata-Version: 1.0 Name: setuptools Version: %s Summary: xxxx Home-page: xxx Author: xxx Author-email: xxx License: xxx Description: xxx """ % SETUPTOOLS_FAKED_VERSION def _install(tarball): # extracting the tarball tmpdir = tempfile.mkdtemp() log.warn('Extracting in %s', tmpdir) old_wd = os.getcwd() try: os.chdir(tmpdir) tar = tarfile.open(tarball) _extractall(tar) tar.close() # going in the directory subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) os.chdir(subdir) log.warn('Now working in %s', subdir) # installing log.warn('Installing Distribute') if not _python_cmd('setup.py', 'install'): log.warn('Something went wrong during the installation.') log.warn('See the error message above.') finally: os.chdir(old_wd) def _build_egg(egg, tarball, to_dir): # extracting the tarball tmpdir = tempfile.mkdtemp() log.warn('Extracting in %s', tmpdir) old_wd = os.getcwd() try: os.chdir(tmpdir) tar = tarfile.open(tarball) _extractall(tar) tar.close() # going in the directory subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) os.chdir(subdir) log.warn('Now working in %s', subdir) # building an egg log.warn('Building a Distribute egg in %s', to_dir) _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) finally: os.chdir(old_wd) # returning the result log.warn(egg) if not os.path.exists(egg): raise IOError('Could not build the egg.') def _do_download(version, download_base, to_dir, download_delay): egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' % (version, sys.version_info[0], sys.version_info[1])) if not os.path.exists(egg): tarball = download_setuptools(version, download_base, to_dir, download_delay) _build_egg(egg, tarball, to_dir) sys.path.insert(0, egg) import setuptools setuptools.bootstrap_install_from = egg def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15, no_fake=True): # making sure we use the absolute path to_dir = os.path.abspath(to_dir) was_imported = 'pkg_resources' in sys.modules or \ 'setuptools' in sys.modules try: try: import pkg_resources if not hasattr(pkg_resources, '_distribute'): if not no_fake: _fake_setuptools() raise ImportError except ImportError: return _do_download(version, download_base, to_dir, download_delay) try: pkg_resources.require("distribute>="+version) return except pkg_resources.VersionConflict: e = sys.exc_info()[1] if was_imported: sys.stderr.write( "The required version of distribute (>=%s) is not available,\n" "and can't be installed while this script is running. Please\n" "install a more recent version first, using\n" "'easy_install -U distribute'." "\n\n(Currently using %r)\n" % (version, e.args[0])) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok return _do_download(version, download_base, to_dir, download_delay) except pkg_resources.DistributionNotFound: return _do_download(version, download_base, to_dir, download_delay) finally: if not no_fake: _create_fake_setuptools_pkg_info(to_dir) def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay=15): """Download distribute from a specified location and return its filename `version` should be a valid distribute version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ # making sure we use the absolute path to_dir = os.path.abspath(to_dir) try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen tgz_name = "distribute-%s.tar.gz" % version url = download_base + tgz_name saveto = os.path.join(to_dir, tgz_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: log.warn("Downloading %s", url) src = urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = src.read() dst = open(saveto, "wb") dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def _no_sandbox(function): def __no_sandbox(*args, **kw): try: from setuptools.sandbox import DirectorySandbox if not hasattr(DirectorySandbox, '_old'): def violation(*args): pass DirectorySandbox._old = DirectorySandbox._violation DirectorySandbox._violation = violation patched = True else: patched = False except ImportError: patched = False try: return function(*args, **kw) finally: if patched: DirectorySandbox._violation = DirectorySandbox._old del DirectorySandbox._old return __no_sandbox def _patch_file(path, content): """Will backup the file then patch it""" existing_content = open(path).read() if existing_content == content: # already patched log.warn('Already patched.') return False log.warn('Patching...') _rename_path(path) f = open(path, 'w') try: f.write(content) finally: f.close() return True _patch_file = _no_sandbox(_patch_file) def _same_content(path, content): return open(path).read() == content def _rename_path(path): new_name = path + '.OLD.%s' % time.time() log.warn('Renaming %s into %s', path, new_name) os.rename(path, new_name) return new_name def _remove_flat_installation(placeholder): if not os.path.isdir(placeholder): log.warn('Unkown installation at %s', placeholder) return False found = False for file in os.listdir(placeholder): if fnmatch.fnmatch(file, 'setuptools*.egg-info'): found = True break if not found: log.warn('Could not locate setuptools*.egg-info') return log.warn('Removing elements out of the way...') pkg_info = os.path.join(placeholder, file) if os.path.isdir(pkg_info): patched = _patch_egg_dir(pkg_info) else: patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) if not patched: log.warn('%s already patched.', pkg_info) return False # now let's move the files out of the way for element in ('setuptools', 'pkg_resources.py', 'site.py'): element = os.path.join(placeholder, element) if os.path.exists(element): _rename_path(element) else: log.warn('Could not find the %s element of the ' 'Setuptools distribution', element) return True _remove_flat_installation = _no_sandbox(_remove_flat_installation) def _after_install(dist): log.warn('After install bootstrap.') placeholder = dist.get_command_obj('install').install_purelib _create_fake_setuptools_pkg_info(placeholder) def _create_fake_setuptools_pkg_info(placeholder): if not placeholder or not os.path.exists(placeholder): log.warn('Could not find the install location') return pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) setuptools_file = 'setuptools-%s-py%s.egg-info' % \ (SETUPTOOLS_FAKED_VERSION, pyver) pkg_info = os.path.join(placeholder, setuptools_file) if os.path.exists(pkg_info): log.warn('%s already exists', pkg_info) return log.warn('Creating %s', pkg_info) f = open(pkg_info, 'w') try: f.write(SETUPTOOLS_PKG_INFO) finally: f.close() pth_file = os.path.join(placeholder, 'setuptools.pth') log.warn('Creating %s', pth_file) f = open(pth_file, 'w') try: f.write(os.path.join(os.curdir, setuptools_file)) finally: f.close() _create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info) def _patch_egg_dir(path): # let's check if it's already patched pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') if os.path.exists(pkg_info): if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): log.warn('%s already patched.', pkg_info) return False _rename_path(path) os.mkdir(path) os.mkdir(os.path.join(path, 'EGG-INFO')) pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') f = open(pkg_info, 'w') try: f.write(SETUPTOOLS_PKG_INFO) finally: f.close() return True _patch_egg_dir = _no_sandbox(_patch_egg_dir) def _before_install(): log.warn('Before install bootstrap.') _fake_setuptools() def _under_prefix(location): if 'install' not in sys.argv: return True args = sys.argv[sys.argv.index('install')+1:] for index, arg in enumerate(args): for option in ('--root', '--prefix'): if arg.startswith('%s=' % option): top_dir = arg.split('root=')[-1] return location.startswith(top_dir) elif arg == option: if len(args) > index: top_dir = args[index+1] return location.startswith(top_dir) if arg == '--user' and USER_SITE is not None: return location.startswith(USER_SITE) return True def _fake_setuptools(): log.warn('Scanning installed packages') try: import pkg_resources except ImportError: # we're cool log.warn('Setuptools or Distribute does not seem to be installed.') return ws = pkg_resources.working_set try: setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', replacement=False)) except TypeError: # old distribute API setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) if setuptools_dist is None: log.warn('No setuptools distribution found') return # detecting if it was already faked setuptools_location = setuptools_dist.location log.warn('Setuptools installation detected at %s', setuptools_location) # if --root or --preix was provided, and if # setuptools is not located in them, we don't patch it if not _under_prefix(setuptools_location): log.warn('Not patching, --root or --prefix is installing Distribute' ' in another location') return # let's see if its an egg if not setuptools_location.endswith('.egg'): log.warn('Non-egg installation') res = _remove_flat_installation(setuptools_location) if not res: return else: log.warn('Egg installation') pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') if (os.path.exists(pkg_info) and _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): log.warn('Already patched.') return log.warn('Patching...') # let's create a fake egg replacing setuptools one res = _patch_egg_dir(setuptools_location) if not res: return log.warn('Patched done.') _relaunch() def _relaunch(): log.warn('Relaunching...') # we have to relaunch the process # pip marker to avoid a relaunch bug if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']: sys.argv[0] = 'setup.py' args = [sys.executable] + sys.argv sys.exit(subprocess.call(args)) def _extractall(self, path=".", members=None): """Extract all members from the archive to the current working directory and set owner, modification time and permissions on directories afterwards. `path' specifies a different directory to extract to. `members' is optional and must be a subset of the list returned by getmembers(). """ import copy import operator from tarfile import ExtractError directories = [] if members is None: members = self for tarinfo in members: if tarinfo.isdir(): # Extract directories with a safe mode. directories.append(tarinfo) tarinfo = copy.copy(tarinfo) tarinfo.mode = 448 # decimal for oct 0700 self.extract(tarinfo, path) # Reverse sort directories. if sys.version_info < (2, 4): def sorter(dir1, dir2): return cmp(dir1.name, dir2.name) directories.sort(sorter) directories.reverse() else: directories.sort(key=operator.attrgetter('name'), reverse=True) # Set correct owner, mtime and filemode on directories. for tarinfo in directories: dirpath = os.path.join(path, tarinfo.name) try: self.chown(tarinfo, dirpath) self.utime(tarinfo, dirpath) self.chmod(tarinfo, dirpath) except ExtractError: e = sys.exc_info()[1] if self.errorlevel > 1: raise else: self._dbg(1, "tarfile: %s" % e) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" tarball = download_setuptools() _install(tarball) if __name__ == '__main__': import os os.environ.set("HTTP_HOST",r"http//ldnproxy.ldn.emea.cib:9090") main(sys.argv[1:]) python-graph-1.8.2/docs/0000755000175000017500000000000012016145554014131 5ustar morphmorphpython-graph-1.8.2/docs/redirect.html0000644000175000017500000000527412016145554016630 0ustar morphmorphEpydoc Redirect Page

Epydoc Auto-redirect page

When javascript is enabled, this page will redirect URLs of the form redirect.html#dotted.name to the documentation for the object with the given fully-qualified dotted name.

 

python-graph-1.8.2/docs/pygraph.readwrite.markup-module.html0000644000175000017500000002602712016145552023244 0ustar morphmorph pygraph.readwrite.markup
Package pygraph :: Package readwrite :: Module markup

Module markup

Functions for reading and writing graphs in a XML markup.

Functions
graph
read(string)
Read a graph from a XML document and return it.
hypergraph
read_hypergraph(string)
Read a graph from a XML document.
string
write(G)
Return a string specifying the given graph as a XML document.
string
write_hypergraph(hgr)
Return a string specifying the given hypergraph as a XML document.
Variables
  __package__ = 'pygraph.readwrite'
Function Details

read(string)

 

Read a graph from a XML document and return it. Nodes and edges specified in the input will be added to the current graph.

Parameters:
  • string (string) - Input string in XML format specifying a graph.
Returns: graph
Graph

read_hypergraph(string)

 

Read a graph from a XML document. Nodes and hyperedges specified in the input will be added to the current graph.

Parameters:
  • string (string) - Input string in XML format specifying a graph.
Returns: hypergraph
Hypergraph

write(G)

 

Return a string specifying the given graph as a XML document.

Parameters:
  • G (graph) - Graph.
Returns: string
String specifying the graph as a XML document.

write_hypergraph(hgr)

 

Return a string specifying the given hypergraph as a XML document.

Parameters:
  • hgr (hypergraph) - Hypergraph.
Returns: string
String specifying the graph as a XML document.

python-graph-1.8.2/docs/pygraph.readwrite-module.html0000644000175000017500000001171212016145552021741 0ustar morphmorph pygraph.readwrite
Package pygraph :: Package readwrite

Package readwrite

Readwrite algorithms.

Algorithms for reading and writing graphs.

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.mixins.labeling.labeling-class.html0000644000175000017500000006707112016145554024445 0ustar morphmorph pygraph.mixins.labeling.labeling
Package pygraph :: Package mixins :: Module labeling :: Class labeling

Class labeling


Generic labeling support for graphs

Instance Methods
boolean
__eq__(self, other)
Return whether this graph is equal to another one.
 
__init__(self)
x.__init__(...) initializes x; see help(type(x)) for signature
 
add_edge_attribute(self, edge, attr)
Add attribute to the given edge.
 
add_edge_attributes(self, edge, attrs)
Append a sequence of attributes to the given edge
 
add_node_attribute(self, node, attr)
Add attribute to the given node.
 
del_edge_labeling(self, edge)
 
del_node_labeling(self, node)
list
edge_attributes(self, edge)
Return the attributes of the given edge.
string
edge_label(self, edge)
Get the label of an edge.
number
edge_weight(self, edge)
Get the weight of an edge.
 
get_edge_properties(self, edge)
list
node_attributes(self, node)
Return the attributes of the given node.
 
set_edge_label(self, edge, label)
Set the label of an edge.
 
set_edge_properties(self, edge, **properties)
 
set_edge_weight(self, edge, wt)
Set the weight of an edge.

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Class Variables
  WEIGHT_ATTRIBUTE_NAME = 'weight'
  DEFAULT_WEIGHT = 1
  LABEL_ATTRIBUTE_NAME = 'label'
  DEFAULT_LABEL = ''
Properties

Inherited from object: __class__

Method Details

__eq__(self, other)
(Equality operator)

 

Return whether this graph is equal to another one.

Parameters:
  • other (graph, digraph) - Other graph or digraph
Returns: boolean
Whether this graph and the other are equal.

__init__(self)
(Constructor)

 

x.__init__(...) initializes x; see help(type(x)) for signature

Overrides: object.__init__
(inherited documentation)

add_edge_attribute(self, edge, attr)

 

Add attribute to the given edge.

Parameters:
  • edge (edge) - One edge.
  • attr (tuple) - Node attribute specified as a tuple in the form (attribute, value).

add_edge_attributes(self, edge, attrs)

 

Append a sequence of attributes to the given edge

Parameters:
  • edge (edge) - One edge.
  • attrs (tuple) - Node attributes specified as a sequence of tuples in the form (attribute, value).

add_node_attribute(self, node, attr)

 

Add attribute to the given node.

Parameters:
  • node (node) - Node identifier
  • attr (tuple) - Node attribute specified as a tuple in the form (attribute, value).

edge_attributes(self, edge)

 

Return the attributes of the given edge.

Parameters:
  • edge (edge) - One edge.
Returns: list
List of attributes specified tuples in the form (attribute, value).

edge_label(self, edge)

 

Get the label of an edge.

Parameters:
  • edge (edge) - One edge.
Returns: string
Edge label

edge_weight(self, edge)

 

Get the weight of an edge.

Parameters:
  • edge (edge) - One edge.
Returns: number
Edge weight.

node_attributes(self, node)

 

Return the attributes of the given node.

Parameters:
  • node (node) - Node identifier
Returns: list
List of attributes specified tuples in the form (attribute, value).

set_edge_label(self, edge, label)

 

Set the label of an edge.

Parameters:
  • edge (edge) - One edge.
  • label (string) - Edge label.

set_edge_weight(self, edge, wt)

 

Set the weight of an edge.

Parameters:
  • edge (edge) - One edge.
  • wt (number) - Edge weight.

python-graph-1.8.2/docs/pygraph.mixins.labeling-module.html0000644000175000017500000001171412016145552023040 0ustar morphmorph pygraph.mixins.labeling
Package pygraph :: Package mixins :: Module labeling

Module labeling

Classes
  labeling
Generic labeling support for graphs
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.mixins.common.common-class.html0000644000175000017500000006056412016145554023673 0ustar morphmorph pygraph.mixins.common.common
Package pygraph :: Package mixins :: Module common :: Class common

Class common


Standard methods common to all graph classes.

Instance Methods
boolean
__eq__(self, other)
Return whether this graph is equal to another one.
iterator
__getitem__(self, node)
Return a iterator passing through all neighbors of the given node.
iterator
__iter__(self)
Return a iterator passing through all nodes in the graph.
number
__len__(self)
Return the order of self when requested by len().
string
__repr__(self)
Return a string representing the graph when requested by repr()
string
__str__(self)
Return a string representing the graph when requested by str() (or print).
 
add_graph(self, other)
Add other graph to this graph.
 
add_nodes(self, nodelist)
Add given nodes to the graph.
 
add_spanning_tree(self, st)
Add a spanning tree to the graph.
 
complete(self)
Make the graph a complete graph.
graph
inverse(self)
Return the inverse of the graph.
number
order(self)
Return the order of self, this is defined as the number of nodes in the graph.
digraph
reverse(self)
Generate the reverse of a directed graph, returns an identical graph if not directed.

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __init__, __new__, __reduce__, __reduce_ex__, __setattr__, __sizeof__, __subclasshook__

Properties

Inherited from object: __class__

Method Details

__eq__(self, other)
(Equality operator)

 

Return whether this graph is equal to another one.

Parameters:
  • other (graph, digraph) - Other graph or digraph
Returns: boolean
Whether this graph and the other are equal.

__getitem__(self, node)
(Indexing operator)

 

Return a iterator passing through all neighbors of the given node.

Returns: iterator
Iterator passing through all neighbors of the given node.

__iter__(self)

 

Return a iterator passing through all nodes in the graph.

Returns: iterator
Iterator passing through all nodes in the graph.

__len__(self)
(Length operator)

 

Return the order of self when requested by len().

Returns: number
Size of the graph.

__repr__(self)
(Representation operator)

 

Return a string representing the graph when requested by repr()

Returns: string
String representing the graph.
Overrides: object.__repr__

__str__(self)
(Informal representation operator)

 

Return a string representing the graph when requested by str() (or print).

Returns: string
String representing the graph.
Overrides: object.__str__

add_graph(self, other)

 

Add other graph to this graph.

Parameters:
  • other (graph) - Graph

Attention: Attributes and labels are not preserved.

add_nodes(self, nodelist)

 

Add given nodes to the graph.

Parameters:
  • nodelist (list) - List of nodes to be added to the graph.

Attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). Objects used to identify nodes absolutely must be hashable. If you need attach a mutable or non-hashable node, consider using the labeling feature.

add_spanning_tree(self, st)

 

Add a spanning tree to the graph.

Parameters:
  • st (dictionary) - Spanning tree.

complete(self)

 

Make the graph a complete graph.

Attention: This will modify the current graph.

inverse(self)

 

Return the inverse of the graph.

Returns: graph
Complement graph for the graph.

order(self)

 

Return the order of self, this is defined as the number of nodes in the graph.

Returns: number
Size of the graph.

reverse(self)

 

Generate the reverse of a directed graph, returns an identical graph if not directed. Attributes & weights are preserved.

Returns: digraph
The directed graph that should be reversed.

python-graph-1.8.2/docs/pygraph.mixins.common-module.html0000644000175000017500000001171212016145552022551 0ustar morphmorph pygraph.mixins.common
Package pygraph :: Package mixins :: Module common

Module common

Classes
  common
Standard methods common to all graph classes.
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.mixins.basegraph.basegraph-class.html0000644000175000017500000001437212016145554024777 0ustar morphmorph pygraph.mixins.basegraph.basegraph
Package pygraph :: Package mixins :: Module basegraph :: Class basegraph

Class basegraph


An abstract class intended as a common ancestor to all graph classes. This allows the user to test isinstance(X, basegraph) to determine if the object is one of any of the python-graph main classes.

Instance Methods

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __init__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Properties

Inherited from object: __class__

python-graph-1.8.2/docs/pygraph.mixins.basegraph-module.html0000644000175000017500000001177512016145552023226 0ustar morphmorph pygraph.mixins.basegraph
Package pygraph :: Package mixins :: Module basegraph

Module basegraph

Classes
  basegraph
An abstract class intended as a common ancestor to all graph classes.
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.mixins-module.html0000644000175000017500000001224212016145552021261 0ustar morphmorph pygraph.mixins
Package pygraph :: Package mixins

Package mixins

Mixins.

Base classes used to compose the the graph classes.

The classes in this namespace should not be used directly.

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.classes.hypergraph.hypergraph-class.html0000644000175000017500000012576612016145554025571 0ustar morphmorph pygraph.classes.hypergraph.hypergraph
Package pygraph :: Package classes :: Module hypergraph :: Class hypergraph

Class hypergraph


Hypergraph class.

Hypergraphs are a generalization of graphs where an edge (called hyperedge) can connect more than two nodes.

Instance Methods
 
__init__(self)
Initialize a hypergraph.
 
add_hyperedge(self, hyperedge)
Add given hyperedge to the hypergraph.
 
add_hyperedges(self, edgelist)
Add given hyperedges to the hypergraph.
 
add_node(self, node)
Add given node to the hypergraph.
 
del_edge(self, hyperedge)
Delete the given hyperedge.
boolean
has_node(self, node)
Return whether the requested node exists.
boolean
has_edge(self, hyperedge)
Return whether the requested node exists.
boolean
has_hyperedge(self, hyperedge)
Return whether the requested node exists.
list
hyperedges(self)
Return hyperedge list.
 
link(self, node, hyperedge)
Link given node and hyperedge.
list
links(self, obj)
Return all nodes connected by the given hyperedge or all hyperedges connected to the given hypernode.
list
nodes(self)
Return node list.
 
unlink(self, node, hyperedge)
Unlink given node and hyperedge.
list
edges(self)
Return the hyperedge list.
list
neighbors(self, obj)
Return all neighbors adjacent to the given node.
 
del_node(self, node)
Delete a given node from the hypergraph.
 
add_edge(self, hyperedge)
Add given hyperedge to the hypergraph.
 
add_edges(self, edgelist)
Add given hyperedges to the hypergraph.
 
del_hyperedge(self, hyperedge)
Delete the given hyperedge.
int
rank(self)
Return the rank of the given hypergraph.
boolean
__eq__(self, other)
Return whether this hypergraph is equal to another one.
boolean
__ne__(self, other)
Return whether this hypergraph is not equal to another one.

Inherited from mixins.common.common: __len__, __str__, add_nodes, __getitem__, __iter__, __repr__, add_graph, add_spanning_tree, complete, inverse, order, reverse

Inherited from mixins.labeling.labeling: add_edge_attribute, add_edge_attributes, add_node_attribute, del_edge_labeling, del_node_labeling, edge_attributes, edge_label, edge_weight, get_edge_properties, node_attributes, set_edge_label, set_edge_properties, set_edge_weight

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __sizeof__, __subclasshook__

Class Variables
  DIRECTED = True

Inherited from mixins.labeling.labeling: DEFAULT_LABEL, DEFAULT_WEIGHT, LABEL_ATTRIBUTE_NAME, WEIGHT_ATTRIBUTE_NAME

Properties

Inherited from object: __class__

Method Details

__init__(self)
(Constructor)

 

Initialize a hypergraph.

Overrides: object.__init__

add_hyperedge(self, hyperedge)

 

Add given hyperedge to the hypergraph.

Parameters:
  • hyperedge (hyperedge) - Hyperedge identifier.

Attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write().

add_hyperedges(self, edgelist)

 

Add given hyperedges to the hypergraph.

Parameters:
  • edgelist (list) - List of hyperedge-nodes to be added to the graph.

Attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write().

add_node(self, node)

 

Add given node to the hypergraph.

Parameters:
  • node (node) - Node identifier.

Attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write().

del_edge(self, hyperedge)

 

Delete the given hyperedge.

Parameters:
  • hyperedge (hyperedge) - Hyperedge identifier.

has_node(self, node)

 

Return whether the requested node exists.

Parameters:
  • node (node) - Node identifier
Returns: boolean
Truth-value for node existence.

has_edge(self, hyperedge)

 

Return whether the requested node exists.

Parameters:
  • hyperedge (hyperedge) - Hyperedge identifier
Returns: boolean
Truth-value for hyperedge existence.

has_hyperedge(self, hyperedge)

 

Return whether the requested node exists.

Parameters:
  • hyperedge (hyperedge) - Hyperedge identifier
Returns: boolean
Truth-value for hyperedge existence.

hyperedges(self)

 

Return hyperedge list.

Returns: list
List of hyperedges in the graph.

link(self, node, hyperedge)

 

Link given node and hyperedge.

Parameters:
  • node (node) - Node.
  • hyperedge (node) - Hyperedge.

links(self, obj)

 

Return all nodes connected by the given hyperedge or all hyperedges connected to the given hypernode.

Parameters:
  • obj (hyperedge) - Object identifier.
Returns: list
List of node objects linked to the given hyperedge.

nodes(self)

 

Return node list.

Returns: list
Node list.

unlink(self, node, hyperedge)

 

Unlink given node and hyperedge.

Parameters:
  • node (node) - Node.
  • hyperedge (hyperedge) - Hyperedge.

edges(self)

 

Return the hyperedge list.

Returns: list
List of hyperedges in the graph.

neighbors(self, obj)

 

Return all neighbors adjacent to the given node.

Parameters:
  • obj (node) - Object identifier.
Returns: list
List of all node objects adjacent to the given node.

del_node(self, node)

 

Delete a given node from the hypergraph.

Parameters:
  • node (node) - Node identifier.

add_edge(self, hyperedge)

 

Add given hyperedge to the hypergraph.

Parameters:
  • hyperedge (hyperedge) - Hyperedge identifier.

Attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write().

add_edges(self, edgelist)

 

Add given hyperedges to the hypergraph.

Parameters:
  • edgelist (list) - List of hyperedge-nodes to be added to the graph.

Attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write().

del_hyperedge(self, hyperedge)

 

Delete the given hyperedge.

Parameters:
  • hyperedge (hyperedge) - Hyperedge identifier.

rank(self)

 

Return the rank of the given hypergraph.

Returns: int
Rank of graph.

__eq__(self, other)
(Equality operator)

 

Return whether this hypergraph is equal to another one.

Parameters:
  • other (hypergraph) - Other hypergraph
Returns: boolean
Whether this hypergraph and the other are equal.
Overrides: mixins.labeling.labeling.__eq__

__ne__(self, other)

 

Return whether this hypergraph is not equal to another one.

Parameters:
  • other (hypergraph) - Other hypergraph
Returns: boolean
Whether this hypergraph and the other are different.

python-graph-1.8.2/docs/pygraph.classes.hypergraph-module.html0000644000175000017500000001215212016145552023557 0ustar morphmorph pygraph.classes.hypergraph
Package pygraph :: Package classes :: Module hypergraph

Module hypergraph

Hypergraph class

Classes
  hypergraph
Hypergraph class.
Variables
  __package__ = 'pygraph.classes'
python-graph-1.8.2/docs/pygraph.classes.graph.graph-class.html0000644000175000017500000007414512016145554023443 0ustar morphmorph pygraph.classes.graph.graph
Package pygraph :: Package classes :: Module graph :: Class graph

Class graph


Graph class.

Graphs are built of nodes and edges.

Instance Methods
boolean
__eq__(self, other)
Return whether this graph is equal to another one.
 
__init__(self)
Initialize a graph.
boolean
__ne__(self, other)
Return whether this graph is not equal to another one.
 
add_edge(self, edge, wt=1, label='', attrs=[])
Add an edge to the graph connecting two nodes.
 
add_node(self, node, attrs=None)
Add given node to the graph.
 
del_edge(self, edge)
Remove an edge from the graph.
 
del_node(self, node)
Remove a node from the graph.
list
edges(self)
Return all edges in the graph.
boolean
has_edge(self, edge)
Return whether an edge exists.
boolean
has_node(self, node)
Return whether the requested node exists.
list
neighbors(self, node)
Return all nodes that are directly accessible from given node.
number
node_order(self, node)
Return the order of the graph
list
nodes(self)
Return node list.

Inherited from mixins.common.common: __getitem__, __iter__, __len__, __repr__, __str__, add_graph, add_nodes, add_spanning_tree, complete, inverse, order, reverse

Inherited from mixins.labeling.labeling: add_edge_attribute, add_edge_attributes, add_node_attribute, del_edge_labeling, del_node_labeling, edge_attributes, edge_label, edge_weight, get_edge_properties, node_attributes, set_edge_label, set_edge_properties, set_edge_weight

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __sizeof__, __subclasshook__

Class Variables
  DIRECTED = False

Inherited from mixins.labeling.labeling: DEFAULT_LABEL, DEFAULT_WEIGHT, LABEL_ATTRIBUTE_NAME, WEIGHT_ATTRIBUTE_NAME

Properties

Inherited from object: __class__

Method Details

__eq__(self, other)
(Equality operator)

 

Return whether this graph is equal to another one.

Parameters:
  • other (graph, digraph) - Other graph or digraph
Returns: boolean
Whether this graph and the other are equal.
Overrides: mixins.labeling.labeling.__eq__

__init__(self)
(Constructor)

 

Initialize a graph.

Overrides: object.__init__

__ne__(self, other)

 

Return whether this graph is not equal to another one.

Parameters:
  • other (graph, digraph) - Other graph or digraph
Returns: boolean
Whether this graph and the other are different.

add_edge(self, edge, wt=1, label='', attrs=[])

 

Add an edge to the graph connecting two nodes.

An edge, here, is a pair of nodes like (n, m).

Parameters:
  • edge (tuple) - Edge.
  • wt (number) - Edge weight.
  • label (string) - Edge label.
  • attrs (list) - List of node attributes specified as (attribute, value) tuples.

add_node(self, node, attrs=None)

 

Add given node to the graph.

Parameters:
  • node (node) - Node identifier.
  • attrs (list) - List of node attributes specified as (attribute, value) tuples.

Attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write().

del_edge(self, edge)

 

Remove an edge from the graph.

Parameters:
  • edge (tuple) - Edge.

del_node(self, node)

 

Remove a node from the graph.

Parameters:
  • node (node) - Node identifier.

edges(self)

 

Return all edges in the graph.

Returns: list
List of all edges in the graph.

has_edge(self, edge)

 

Return whether an edge exists.

Parameters:
  • edge (tuple) - Edge.
Returns: boolean
Truth-value for edge existence.

has_node(self, node)

 

Return whether the requested node exists.

Parameters:
  • node (node) - Node identifier
Returns: boolean
Truth-value for node existence.

neighbors(self, node)

 

Return all nodes that are directly accessible from given node.

Parameters:
  • node (node) - Node identifier
Returns: list
List of nodes directly accessible from given node.

node_order(self, node)

 

Return the order of the graph

Returns: number
Order of the given node.

nodes(self)

 

Return node list.

Returns: list
Node list.

python-graph-1.8.2/docs/pygraph.classes.graph-module.html0000644000175000017500000001210212016145552022502 0ustar morphmorph pygraph.classes.graph
Package pygraph :: Package classes :: Module graph

Module graph

Graph class

Classes
  graph
Graph class.
Variables
  __package__ = 'pygraph.classes'
python-graph-1.8.2/docs/pygraph.classes.exceptions.NodeUnreachable-class.html0000644000175000017500000002126412016145554026433 0ustar morphmorph pygraph.classes.exceptions.NodeUnreachable
Package pygraph :: Package classes :: Module exceptions :: Class NodeUnreachable

Class NodeUnreachable


Goal could not be reached from start.

Instance Methods
 
__init__(self, start, goal)
x.__init__(...) initializes x; see help(type(x)) for signature

Inherited from exceptions.RuntimeError: __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__, __unicode__

Inherited from object: __format__, __hash__, __reduce_ex__, __sizeof__, __subclasshook__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

Method Details

__init__(self, start, goal)
(Constructor)

 

x.__init__(...) initializes x; see help(type(x)) for signature

Overrides: object.__init__
(inherited documentation)

python-graph-1.8.2/docs/pygraph.classes.exceptions.NegativeWeightCycleError-class.html0000644000175000017500000001610112016145554030312 0ustar morphmorph pygraph.classes.exceptions.NegativeWeightCycleError
Package pygraph :: Package classes :: Module exceptions :: Class NegativeWeightCycleError

Class NegativeWeightCycleError


Algorithms like the Bellman-Ford algorithm can detect and raise an exception when they encounter a negative weight cycle.


See Also: pygraph.algorithms.shortest_path_bellman_ford

Instance Methods

Inherited from exceptions.RuntimeError: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__, __unicode__

Inherited from object: __format__, __hash__, __reduce_ex__, __sizeof__, __subclasshook__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

python-graph-1.8.2/docs/pygraph.classes.exceptions.InvalidGraphType-class.html0000644000175000017500000001544312016145554026630 0ustar morphmorph pygraph.classes.exceptions.InvalidGraphType
Package pygraph :: Package classes :: Module exceptions :: Class InvalidGraphType

Class InvalidGraphType


Invalid graph type.

Instance Methods

Inherited from exceptions.RuntimeError: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__, __unicode__

Inherited from object: __format__, __hash__, __reduce_ex__, __sizeof__, __subclasshook__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

python-graph-1.8.2/docs/pygraph.classes.exceptions.GraphError-class.html0000644000175000017500000001620312016145554025464 0ustar morphmorph pygraph.classes.exceptions.GraphError
Package pygraph :: Package classes :: Module exceptions :: Class GraphError

Class GraphError


A base-class for the various kinds of errors that occur in the the python-graph class.

Instance Methods

Inherited from exceptions.RuntimeError: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__, __unicode__

Inherited from object: __format__, __hash__, __reduce_ex__, __sizeof__, __subclasshook__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

python-graph-1.8.2/docs/pygraph.classes.exceptions.AlgorithmError-class.html0000644000175000017500000001557212016145554026361 0ustar morphmorph pygraph.classes.exceptions.AlgorithmError
Package pygraph :: Package classes :: Module exceptions :: Class AlgorithmError

Class AlgorithmError


A base-class for the various kinds of errors that occur in the the algorithms package.

Instance Methods

Inherited from exceptions.RuntimeError: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__, __unicode__

Inherited from object: __format__, __hash__, __reduce_ex__, __sizeof__, __subclasshook__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

python-graph-1.8.2/docs/pygraph.classes.exceptions.AdditionError-class.html0000644000175000017500000001554112016145554026162 0ustar morphmorph pygraph.classes.exceptions.AdditionError
Package pygraph :: Package classes :: Module exceptions :: Class AdditionError

Class AdditionError


This error is raised when trying to add a node or edge already added to the graph or digraph.

Instance Methods

Inherited from exceptions.RuntimeError: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__, __unicode__

Inherited from object: __format__, __hash__, __reduce_ex__, __sizeof__, __subclasshook__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

python-graph-1.8.2/docs/pygraph.classes.exceptions-module.html0000644000175000017500000001554312016145552023576 0ustar morphmorph pygraph.classes.exceptions
Package pygraph :: Package classes :: Module exceptions

Module exceptions

Exceptions.

Classes
  GraphError
A base-class for the various kinds of errors that occur in the the python-graph class.
  AdditionError
This error is raised when trying to add a node or edge already added to the graph or digraph.
  NodeUnreachable
Goal could not be reached from start.
  InvalidGraphType
Invalid graph type.
  AlgorithmError
A base-class for the various kinds of errors that occur in the the algorithms package.
  NegativeWeightCycleError
Algorithms like the Bellman-Ford algorithm can detect and raise an exception when they encounter a negative weight cycle.
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.classes.digraph.digraph-class.html0000644000175000017500000007737012016145554024300 0ustar morphmorph pygraph.classes.digraph.digraph
Package pygraph :: Package classes :: Module digraph :: Class digraph

Class digraph


Digraph class.

Digraphs are built of nodes and directed edges.

Instance Methods
boolean
__eq__(self, other)
Return whether this graph is equal to another one.
 
__init__(self)
Initialize a digraph.
boolean
__ne__(self, other)
Return whether this graph is not equal to another one.
 
add_edge(self, edge, wt=1, label='', attrs=[])
Add an directed edge to the graph connecting two nodes.
 
add_node(self, node, attrs=None)
Add given node to the graph.
 
del_edge(self, edge)
Remove an directed edge from the graph.
 
del_node(self, node)
Remove a node from the graph.
list
edges(self)
Return all edges in the graph.
boolean
has_edge(self, edge)
Return whether an edge exists.
boolean
has_node(self, node)
Return whether the requested node exists.
list
incidents(self, node)
Return all nodes that are incident to the given node.
list
neighbors(self, node)
Return all nodes that are directly accessible from given node.
number
node_order(self, node)
Return the order of the given node.
list
nodes(self)
Return node list.

Inherited from mixins.common.common: __getitem__, __iter__, __len__, __repr__, __str__, add_graph, add_nodes, add_spanning_tree, complete, inverse, order, reverse

Inherited from mixins.labeling.labeling: add_edge_attribute, add_edge_attributes, add_node_attribute, del_edge_labeling, del_node_labeling, edge_attributes, edge_label, edge_weight, get_edge_properties, node_attributes, set_edge_label, set_edge_properties, set_edge_weight

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __sizeof__, __subclasshook__

Class Variables
  DIRECTED = True

Inherited from mixins.labeling.labeling: DEFAULT_LABEL, DEFAULT_WEIGHT, LABEL_ATTRIBUTE_NAME, WEIGHT_ATTRIBUTE_NAME

Properties

Inherited from object: __class__

Method Details

__eq__(self, other)
(Equality operator)

 

Return whether this graph is equal to another one.

Parameters:
  • other (graph, digraph) - Other graph or digraph
Returns: boolean
Whether this graph and the other are equal.
Overrides: mixins.labeling.labeling.__eq__

__init__(self)
(Constructor)

 

Initialize a digraph.

Overrides: object.__init__

__ne__(self, other)

 

Return whether this graph is not equal to another one.

Parameters:
  • other (graph, digraph) - Other graph or digraph
Returns: boolean
Whether this graph and the other are different.

add_edge(self, edge, wt=1, label='', attrs=[])

 

Add an directed edge to the graph connecting two nodes.

An edge, here, is a pair of nodes like (n, m).

Parameters:
  • edge (tuple) - Edge.
  • wt (number) - Edge weight.
  • label (string) - Edge label.
  • attrs (list) - List of node attributes specified as (attribute, value) tuples.

add_node(self, node, attrs=None)

 

Add given node to the graph.

Parameters:
  • node (node) - Node identifier.
  • attrs (list) - List of node attributes specified as (attribute, value) tuples.

Attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write().

del_edge(self, edge)

 

Remove an directed edge from the graph.

Parameters:
  • edge (tuple) - Edge.

del_node(self, node)

 

Remove a node from the graph.

Parameters:
  • node (node) - Node identifier.

edges(self)

 

Return all edges in the graph.

Returns: list
List of all edges in the graph.

has_edge(self, edge)

 

Return whether an edge exists.

Parameters:
  • edge (tuple) - Edge.
Returns: boolean
Truth-value for edge existence.

has_node(self, node)

 

Return whether the requested node exists.

Parameters:
  • node (node) - Node identifier
Returns: boolean
Truth-value for node existence.

incidents(self, node)

 

Return all nodes that are incident to the given node.

Parameters:
  • node (node) - Node identifier
Returns: list
List of nodes directly accessible from given node.

neighbors(self, node)

 

Return all nodes that are directly accessible from given node.

Parameters:
  • node (node) - Node identifier
Returns: list
List of nodes directly accessible from given node.

node_order(self, node)

 

Return the order of the given node.

Returns: number
Order of the given node.

nodes(self)

 

Return node list.

Returns: list
Node list.

python-graph-1.8.2/docs/pygraph.classes.digraph-module.html0000644000175000017500000001212212016145552023021 0ustar morphmorph pygraph.classes.digraph
Package pygraph :: Package classes :: Module digraph

Module digraph

Digraph class

Classes
  digraph
Digraph class.
Variables
  __package__ = 'pygraph.classes'
python-graph-1.8.2/docs/pygraph.classes-module.html0000644000175000017500000001253212016145552021411 0ustar morphmorph pygraph.classes
Package pygraph :: Package classes

Package classes

Data structure classes.

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.algorithms.utils.priority_queue-class.html0000644000175000017500000002354412016145554026177 0ustar morphmorph pygraph.algorithms.utils.priority_queue
Package pygraph :: Package algorithms :: Module utils :: Class priority_queue

Class priority_queue

Priority queue.

Instance Methods
 
__init__(self, list=[])
 
__contains__(self, item)
 
__len__(self)
 
empty(self)
 
insert(self, item, priority)
Insert item into the queue, with the given priority.
 
pop(self)
Return the item with the lowest priority, and remove it from the queue.
 
peek(self)
Return the item with the lowest priority.
 
discard(self, item)
Method Details

peek(self)

 

Return the item with the lowest priority. The queue is unchanged.


python-graph-1.8.2/docs/pygraph.algorithms.utils.HeapItem-class.html0000644000175000017500000001252612016145554024604 0ustar morphmorph pygraph.algorithms.utils.HeapItem
Package pygraph :: Package algorithms :: Module utils :: Class HeapItem

Class HeapItem

Instance Methods
 
__init__(self, item, priority)
 
__cmp__(self, other)
python-graph-1.8.2/docs/pygraph.algorithms.utils-module.html0000644000175000017500000001257612016145552023274 0ustar morphmorph pygraph.algorithms.utils
Package pygraph :: Package algorithms :: Module utils

Module utils

Miscellaneous useful stuff.

Classes
  priority_queue
Priority queue.
  HeapItem
Variables
  __package__ = 'pygraph.algorithms'
python-graph-1.8.2/docs/pygraph.algorithms.traversal-module.html0000644000175000017500000001603112016145552024125 0ustar morphmorph pygraph.algorithms.traversal
Package pygraph :: Package algorithms :: Module traversal

Module traversal

Traversal algorithms.

Functions
iterator
traversal(graph, node, order)
Graph traversal iterator.
Variables
  __package__ = None
Function Details

traversal(graph, node, order)

 

Graph traversal iterator.

Parameters:
  • graph (graph, digraph) - Graph.
  • node (node) - Node.
  • order (string) - traversal ordering. Possible values are:
    1. 'pre' - Preordering (default)
    1. 'post' - Postordering
Returns: iterator
Traversal iterator.

python-graph-1.8.2/docs/pygraph.algorithms.sorting-module.html0000644000175000017500000001534212016145552023613 0ustar morphmorph pygraph.algorithms.sorting
Package pygraph :: Package algorithms :: Module sorting

Module sorting

Sorting algorithms.

Functions
list
topological_sorting(graph)
Topological sorting.
Variables
  __package__ = 'pygraph.algorithms'
Function Details

topological_sorting(graph)

 

Topological sorting.

Parameters:
  • graph (digraph) - Graph.
Returns: list
Topological sorting for the graph.

Attention: Topological sorting is meaningful only for directed acyclic graphs.


python-graph-1.8.2/docs/pygraph.algorithms.searching-module.html0000644000175000017500000002264312016145552024073 0ustar morphmorph pygraph.algorithms.searching
Package pygraph :: Package algorithms :: Module searching

Module searching

Search algorithms.

Functions
tuple
breadth_first_search(graph, root=None, filter=null())
Breadth-first search.
tuple
depth_first_search(graph, root=None, filter=null())
Depth-first search.
Variables
  __package__ = 'pygraph.algorithms'
Function Details

breadth_first_search(graph, root=None, filter=null())

 

Breadth-first search.

Parameters:
  • graph (graph, digraph) - Graph.
  • root (node) - Optional root node (will explore only root's connected component)
Returns: tuple
A tuple containing a dictionary and a list.
  1. Generated spanning tree
  2. Graph's level-based ordering

depth_first_search(graph, root=None, filter=null())

 

Depth-first search.

Parameters:
  • graph (graph, digraph) - Graph.
  • root (node) - Optional root node (will explore only root's connected component)
Returns: tuple
A tupple containing a dictionary and two lists:
  1. Generated spanning tree
  2. Graph's preordering
  3. Graph's postordering

python-graph-1.8.2/docs/pygraph.algorithms.pagerank-module.html0000644000175000017500000001662212016145552023720 0ustar morphmorph pygraph.algorithms.pagerank
Package pygraph :: Package algorithms :: Module pagerank

Module pagerank

PageRank algoritm

Functions
Dict
pagerank(graph, damping_factor=0.85, max_iterations=100, min_delta=1e-05)
Compute and return the PageRank in an directed graph.
Variables
  __package__ = None
Function Details

pagerank(graph, damping_factor=0.85, max_iterations=100, min_delta=1e-05)

 

Compute and return the PageRank in an directed graph.

Parameters:
  • graph (digraph) - Digraph.
  • damping_factor (number) - PageRank dumping factor.
  • max_iterations (number) - Maximum number of iterations.
  • min_delta (number) - Smallest variation required to have a new iteration.
Returns: Dict
Dict containing all the nodes PageRank.

python-graph-1.8.2/docs/pygraph.algorithms.minmax-module.html0000644000175000017500000005122212016145552023414 0ustar morphmorph pygraph.algorithms.minmax
Package pygraph :: Package algorithms :: Module minmax

Module minmax

Minimization and maximization algorithms.

Functions
list
heuristic_search(graph, start, goal, heuristic)
A* search algorithm.
dictionary
minimal_spanning_tree(graph, root=None)
Minimal spanning tree.
tuple
shortest_path(graph, source)
Return the shortest path distance between source and all other nodes using Dijkstra's algorithm.
tuple
shortest_path_bellman_ford(graph, source)
Return the shortest path distance between the source node and all other nodes in the graph using Bellman-Ford's algorithm.
tuple
maximum_flow(graph, source, sink, caps=None)
Find a maximum flow and minimum cut of a directed graph by the Edmonds-Karp algorithm.
float
cut_value(graph, flow, cut)
Calculate the value of a cut.
dictionary
cut_tree(igraph, caps=None)
Construct a Gomory-Hu cut tree by applying the algorithm of Gusfield.
Variables
  __package__ = 'pygraph.algorithms'
Function Details

heuristic_search(graph, start, goal, heuristic)

 

A* search algorithm.

A set of heuristics is available under graph.algorithms.heuristics. User-created heuristics are allowed too.

Parameters:
  • graph (graph, digraph) - Graph
  • start (node) - Start node
  • goal (node) - Goal node
  • heuristic (function) - Heuristic function
Returns: list
Optimized path from start to goal node

minimal_spanning_tree(graph, root=None)

 

Minimal spanning tree.

Parameters:
  • graph (graph) - Graph.
  • root (node) - Optional root node (will explore only root's connected component)
Returns: dictionary
Generated spanning tree.

Attention: Minimal spanning tree is meaningful only for weighted graphs.

shortest_path(graph, source)

 

Return the shortest path distance between source and all other nodes using Dijkstra's algorithm.

Parameters:
  • graph (graph, digraph) - Graph.
  • source (node) - Node from which to start the search.
Returns: tuple
A tuple containing two dictionaries, each keyed by target nodes.
  1. Shortest path spanning tree
  2. Shortest distance from given source to each target node

Inaccessible target nodes do not appear in either dictionary.

Attention: All weights must be nonnegative.

See Also: shortest_path_bellman_ford

shortest_path_bellman_ford(graph, source)

 

Return the shortest path distance between the source node and all other nodes in the graph using Bellman-Ford's algorithm.

This algorithm is useful when you have a weighted (and obviously a directed) graph with negative weights.

Parameters:
  • graph (digraph) - Digraph
  • source (node) - Source node of the graph
Returns: tuple
A tuple containing two dictionaries, each keyed by target nodes. (same as shortest_path function that implements Dijkstra's algorithm)
  1. Shortest path spanning tree
  2. Shortest distance from given source to each target node
Raises:
  • NegativeWeightCycleError - raises if it finds a negative weight cycle. If this condition is met d(v) > d(u) + W(u, v) then raise the error.

Attention: The algorithm can detect negative weight cycles and will raise an exception. It's meaningful only for directed weighted graphs.

See Also: shortest_path

maximum_flow(graph, source, sink, caps=None)

 

Find a maximum flow and minimum cut of a directed graph by the Edmonds-Karp algorithm.

Parameters:
  • graph (digraph) - Graph
  • source (node) - Source of the flow
  • sink (node) - Sink of the flow
  • caps (dictionary) - Dictionary specifying a maximum capacity for each edge. If not given, the weight of the edge will be used as its capacity. Otherwise, for each edge (a,b), caps[(a,b)] should be given.
Returns: tuple
A tuple containing two dictionaries
  1. contains the flow through each edge for a maximal flow through the graph
  2. contains to which component of a minimum cut each node belongs

cut_value(graph, flow, cut)

 

Calculate the value of a cut.

Parameters:
  • graph (digraph) - Graph
  • flow (dictionary) - Dictionary containing a flow for each edge.
  • cut (dictionary) - Dictionary mapping each node to a subset index. The function only considers the flow between nodes with 0 and 1.
Returns: float
The value of the flow between the subsets 0 and 1

cut_tree(igraph, caps=None)

 

Construct a Gomory-Hu cut tree by applying the algorithm of Gusfield.

Parameters:
  • igraph (graph) - Graph
  • caps (dictionary) - Dictionary specifying a maximum capacity for each edge. If not given, the weight of the edge will be used as its capacity. Otherwise, for each edge (a,b), caps[(a,b)] should be given.
Returns: dictionary
Gomory-Hu cut tree as a dictionary, where each edge is associated with its weight

python-graph-1.8.2/docs/pygraph.algorithms.heuristics.euclidean.euclidean-class.html0000644000175000017500000003036712016145554030016 0ustar morphmorph pygraph.algorithms.heuristics.euclidean.euclidean
Package pygraph :: Package algorithms :: Package heuristics :: Module euclidean :: Class euclidean

Class euclidean


A* heuristic for Euclidean graphs.

This heuristic has three requirements:

  1. All nodes should have the attribute 'position';
  2. The weight of all edges should be the euclidean distance between the nodes it links;
  3. The optimize() method should be called before the heuristic search.

A small example for clarification:

>>> g = graph.graph()
>>> g.add_nodes(['A','B','C'])
>>> g.add_node_attribute('A', ('position',(0,0)))
>>> g.add_node_attribute('B', ('position',(1,1)))
>>> g.add_node_attribute('C', ('position',(0,2)))
>>> g.add_edge('A','B', wt=2)
>>> g.add_edge('B','C', wt=2)
>>> g.add_edge('A','C', wt=4)
>>> h = graph.heuristics.euclidean()
>>> h.optimize(g)
>>> g.heuristic_search('A', 'C', h)
Instance Methods
 
__init__(self)
Initialize the heuristic object.
 
optimize(self, graph)
Build a dictionary mapping each pair of nodes to a number (the distance between them).
 
__call__(self, start, end)
Estimate how far start is from end.

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Properties

Inherited from object: __class__

Method Details

__init__(self)
(Constructor)

 

Initialize the heuristic object.

Overrides: object.__init__

optimize(self, graph)

 

Build a dictionary mapping each pair of nodes to a number (the distance between them).

Parameters:
  • graph (graph) - Graph.

__call__(self, start, end)
(Call operator)

 

Estimate how far start is from end.

Parameters:
  • start (node) - Start node.
  • end (node) - End node.

python-graph-1.8.2/docs/pygraph.algorithms.heuristics.euclidean-module.html0000644000175000017500000001217512016145552026241 0ustar morphmorph pygraph.algorithms.heuristics.euclidean
Package pygraph :: Package algorithms :: Package heuristics :: Module euclidean

Module euclidean

A* heuristic for euclidean graphs.

Classes
  euclidean
A* heuristic for Euclidean graphs.
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.algorithms.heuristics.chow.chow-class.html0000644000175000017500000002544312016145554026033 0ustar morphmorph pygraph.algorithms.heuristics.chow.chow
Package pygraph :: Package algorithms :: Package heuristics :: Module chow :: Class chow

Class chow


An implementation of the graph searching heuristic proposed by Edmond Chow.

Remember to call the optimize() method before the heuristic search.

For details, check: http://www.edmondchow.com/pubs/levdiff-aaai.pdf.

Instance Methods
 
__init__(self, *centers)
Initialize a Chow heuristic object.
 
optimize(self, graph)
Build a dictionary mapping each pair of nodes to a number (the distance between them).
 
__call__(self, start, end)
Estimate how far start is from end.

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Properties

Inherited from object: __class__

Method Details

__init__(self, *centers)
(Constructor)

 

Initialize a Chow heuristic object.

Overrides: object.__init__

optimize(self, graph)

 

Build a dictionary mapping each pair of nodes to a number (the distance between them).

Parameters:
  • graph (graph) - Graph.

__call__(self, start, end)
(Call operator)

 

Estimate how far start is from end.

Parameters:
  • start (node) - Start node.
  • end (node) - End node.

python-graph-1.8.2/docs/pygraph.algorithms.heuristics.chow-module.html0000644000175000017500000001246112016145552025246 0ustar morphmorph pygraph.algorithms.heuristics.chow
Package pygraph :: Package algorithms :: Package heuristics :: Module chow

Module chow

Edmond Chow's heuristic for A*.

Classes
  chow
An implementation of the graph searching heuristic proposed by Edmond Chow.
Variables
  __package__ = 'pygraph.algorithms.heuristics'
python-graph-1.8.2/docs/pygraph.algorithms.heuristics-module.html0000644000175000017500000001244012016145552024304 0ustar morphmorph pygraph.algorithms.heuristics
Package pygraph :: Package algorithms :: Package heuristics

Package heuristics

Set of search heuristics.

These are to be used with the heuristic_search() function.

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.algorithms.generators-module.html0000644000175000017500000002261512016145552024300 0ustar morphmorph pygraph.algorithms.generators
Package pygraph :: Package algorithms :: Module generators

Module generators

Random graph generators.

Functions
 
generate(num_nodes, num_edges, directed=False, weight_range=(1, 1))
Create a random graph.
 
generate_hypergraph(num_nodes, num_edges, r=0)
Create a random hyper graph.
Variables
  __package__ = 'pygraph.algorithms'
Function Details

generate(num_nodes, num_edges, directed=False, weight_range=(1, 1))

 

Create a random graph.

Parameters:
  • num_nodes (number) - Number of nodes.
  • num_edges (number) - Number of edges.
  • directed (bool) - Whether the generated graph should be directed or not.
  • weight_range (tuple) - tuple of two integers as lower and upper limits on randomly generated weights (uniform distribution).

generate_hypergraph(num_nodes, num_edges, r=0)

 

Create a random hyper graph.

Parameters:
  • num_nodes (number) - Number of nodes.
  • num_edges (number) - Number of edges.
  • r (number) - Uniform edges of size r.

python-graph-1.8.2/docs/pygraph.algorithms.filters.radius.radius-class.html0000644000175000017500000002576112016145554026202 0ustar morphmorph pygraph.algorithms.filters.radius.radius
Package pygraph :: Package algorithms :: Package filters :: Module radius :: Class radius

Class radius


Radial search filter.

This will keep searching contained inside a specified limit.

Instance Methods
 
__init__(self, radius)
Initialize the filter.
 
configure(self, graph, spanning_tree)
Configure the filter.
boolean
__call__(self, node, parent)
Decide if the given node should be included in the search process.

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Properties

Inherited from object: __class__

Method Details

__init__(self, radius)
(Constructor)

 

Initialize the filter.

Parameters:
  • radius (number) - Search radius.
Overrides: object.__init__

configure(self, graph, spanning_tree)

 

Configure the filter.

Parameters:
  • graph (graph) - Graph.
  • spanning_tree (dictionary) - Spanning tree.

__call__(self, node, parent)
(Call operator)

 

Decide if the given node should be included in the search process.

Parameters:
  • node (node) - Given node.
  • parent (node) - Given node's parent in the spanning tree.
Returns: boolean
Whether the given node should be included in the search process.

python-graph-1.8.2/docs/pygraph.algorithms.filters.radius-module.html0000644000175000017500000001210512016145552025056 0ustar morphmorph pygraph.algorithms.filters.radius
Package pygraph :: Package algorithms :: Package filters :: Module radius

Module radius

Radial search filter.

Classes
  radius
Radial search filter.
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.algorithms.filters.null.null-class.html0000644000175000017500000002517112016145554025343 0ustar morphmorph pygraph.algorithms.filters.null.null
Package pygraph :: Package algorithms :: Package filters :: Module null :: Class null

Class null


Null search filter.

Instance Methods
 
__init__(self)
Initialize the filter.
 
configure(self, graph, spanning_tree)
Configure the filter.
boolean
__call__(self, node, parent)
Decide if the given node should be included in the search process.

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Properties

Inherited from object: __class__

Method Details

__init__(self)
(Constructor)

 

Initialize the filter.

Overrides: object.__init__

configure(self, graph, spanning_tree)

 

Configure the filter.

Parameters:
  • graph (graph) - Graph.
  • spanning_tree (dictionary) - Spanning tree.

__call__(self, node, parent)
(Call operator)

 

Decide if the given node should be included in the search process.

Parameters:
  • node (node) - Given node.
  • parent (node) - Given node's parent in the spanning tree.
Returns: boolean
Whether the given node should be included in the search process.

python-graph-1.8.2/docs/pygraph.algorithms.filters.null-module.html0000644000175000017500000001207012016145552024542 0ustar morphmorph pygraph.algorithms.filters.null
Package pygraph :: Package algorithms :: Package filters :: Module null

Module null

Null searching filter.

Classes
  null
Null search filter.
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.algorithms.filters.find.find-class.html0000644000175000017500000002562612016145554025264 0ustar morphmorph pygraph.algorithms.filters.find.find
Package pygraph :: Package algorithms :: Package filters :: Module find :: Class find

Class find


Search filter for finding a specific node.

Instance Methods
 
__init__(self, target)
Initialize the filter.
 
configure(self, graph, spanning_tree)
Configure the filter.
boolean
__call__(self, node, parent)
Decide if the given node should be included in the search process.

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Properties

Inherited from object: __class__

Method Details

__init__(self, target)
(Constructor)

 

Initialize the filter.

Parameters:
  • target (node) - Target node.
Overrides: object.__init__

configure(self, graph, spanning_tree)

 

Configure the filter.

Parameters:
  • graph (graph) - Graph.
  • spanning_tree (dictionary) - Spanning tree.

__call__(self, node, parent)
(Call operator)

 

Decide if the given node should be included in the search process.

Parameters:
  • node (node) - Given node.
  • parent (node) - Given node's parent in the spanning tree.
Returns: boolean
Whether the given node should be included in the search process.

python-graph-1.8.2/docs/pygraph.algorithms.filters.find-module.html0000644000175000017500000001214312016145552024511 0ustar morphmorph pygraph.algorithms.filters.find
Package pygraph :: Package algorithms :: Package filters :: Module find

Module find

Search filter for finding a specific node.

Classes
  find
Search filter for finding a specific node.
Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.algorithms.filters-module.html0000644000175000017500000001255512016145552023601 0ustar morphmorph pygraph.algorithms.filters
Package pygraph :: Package algorithms :: Package filters

Package filters

Set of searching filters.

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph.algorithms.cycles-module.html0000644000175000017500000001526212016145552023411 0ustar morphmorph pygraph.algorithms.cycles
Package pygraph :: Package algorithms :: Module cycles

Module cycles

Cycle detection algorithms.

Functions
list
find_cycle(graph)
Find a cycle in the given graph.
Variables
  __package__ = 'pygraph.algorithms'
Function Details

find_cycle(graph)

 

Find a cycle in the given graph.

This function will return a list of nodes which form a cycle in the graph or an empty list if no cycle exists.

Parameters:
  • graph (graph, digraph) - Graph.
Returns: list
List of nodes.

python-graph-1.8.2/docs/pygraph.algorithms.critical-module.html0000644000175000017500000002124612016145552023720 0ustar morphmorph pygraph.algorithms.critical
Package pygraph :: Package algorithms :: Module critical

Module critical

Critical path algorithms and transitivity detection algorithm.

Functions
List
critical_path(graph)
Compute and return the critical path in an acyclic directed weighted graph.
List
transitive_edges(graph)
Return a list of transitive edges.
Variables
  __package__ = 'pygraph.algorithms'
Function Details

critical_path(graph)

 

Compute and return the critical path in an acyclic directed weighted graph.

Parameters:
  • graph (digraph) - Digraph
Returns: List
List containing all the nodes in the path (or an empty array if the graph contains a cycle)

Attention: This function is only meaningful for directed weighted acyclic graphs

transitive_edges(graph)

 

Return a list of transitive edges.

Example of transitivity within graphs: A -> B, B -> C, A -> C in this case the transitive edge is: A -> C

Parameters:
  • graph (digraph) - Digraph
Returns: List
List containing tuples with transitive edges (or an empty array if the digraph contains a cycle)

Attention: This function is only meaningful for directed acyclic graphs.


python-graph-1.8.2/docs/pygraph.algorithms.accessibility-module.html0000644000175000017500000003110512016145552024750 0ustar morphmorph pygraph.algorithms.accessibility
Package pygraph :: Package algorithms :: Module accessibility

Module accessibility

Accessibility algorithms.

Functions
dictionary
accessibility(graph)
Accessibility matrix (transitive closure).
dictionary
connected_components(graph)
Connected components.
list
cut_edges(graph)
Return the cut-edges of the given graph.
list
cut_nodes(graph)
Return the cut-nodes of the given graph.
dictionary
mutual_accessibility(graph)
Mutual-accessibility matrix (strongly connected components).
Variables
  __package__ = 'pygraph.algorithms'
Function Details

accessibility(graph)

 

Accessibility matrix (transitive closure).

Parameters:
  • graph (graph, digraph, hypergraph) - Graph.
Returns: dictionary
Accessibility information for each node.

connected_components(graph)

 

Connected components.

Parameters:
  • graph (graph, hypergraph) - Graph.
Returns: dictionary
Pairing that associates each node to its connected component.

cut_edges(graph)

 

Return the cut-edges of the given graph.

A cut edge, or bridge, is an edge of a graph whose removal increases the number of connected components in the graph.

Parameters:
  • graph (graph, hypergraph) - Graph.
Returns: list
List of cut-edges.

cut_nodes(graph)

 

Return the cut-nodes of the given graph.

A cut node, or articulation point, is a node of a graph whose removal increases the number of connected components in the graph.

Parameters:
  • graph (graph, hypergraph) - Graph.
Returns: list
List of cut-nodes.

mutual_accessibility(graph)

 

Mutual-accessibility matrix (strongly connected components).

Parameters:
  • graph (graph, digraph) - Graph.
Returns: dictionary
Mutual-accessibility information for each node.

python-graph-1.8.2/docs/pygraph.algorithms-module.html0000644000175000017500000002001512016145552022120 0ustar morphmorph pygraph.algorithms
Package pygraph :: Package algorithms

Package algorithms

Algorithms

This subpackage contains a set of modules, each one of them containing some algorithms.

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/pygraph-module.html0000644000175000017500000003142612016145552017760 0ustar morphmorph pygraph
Package pygraph

Package pygraph

python-graph

A library for working with graphs in Python.


Version: 1.8.2

Data structure classes are located at pygraph.classes.

Exception classes are located at pygraph.classes.exceptions.

Search filters are located at pygraph.algorithms.filters.

Heuristics for the A* algorithm are exposed in pygraph.algorithms.heuristics.

A quick introductory example:

>>> # Import the module and instantiate a graph object
>>> from pygraph.classes.graph import graph
>>> from pygraph.algorithms.searching import depth_first_search
>>> gr = graph()
>>> # Add nodes
>>> gr.add_nodes(['X','Y','Z'])
>>> gr.add_nodes(['A','B','C'])
>>> # Add edges
>>> gr.add_edge(('X','Y'))
>>> gr.add_edge(('X','Z'))
>>> gr.add_edge(('A','B'))
>>> gr.add_edge(('A','C'))
>>> gr.add_edge(('Y','B'))
>>> # Depth first search rooted on node X
>>> st, pre, post = depth_first_search(gr, root='X')
>>> # Print the spanning tree
>>> print st
{'A': 'B', 'C': 'A', 'B': 'Y', 'Y': 'X', 'X': None, 'Z': 'X'}

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/module-tree.html0000644000175000017500000002153412016145552017244 0ustar morphmorph Module Hierarchy
 
[ Module Hierarchy | Class Hierarchy ]

Module Hierarchy

python-graph-1.8.2/docs/index.html0000644000175000017500000003142612016145554016134 0ustar morphmorph pygraph
Package pygraph

Package pygraph

python-graph

A library for working with graphs in Python.


Version: 1.8.2

Data structure classes are located at pygraph.classes.

Exception classes are located at pygraph.classes.exceptions.

Search filters are located at pygraph.algorithms.filters.

Heuristics for the A* algorithm are exposed in pygraph.algorithms.heuristics.

A quick introductory example:

>>> # Import the module and instantiate a graph object
>>> from pygraph.classes.graph import graph
>>> from pygraph.algorithms.searching import depth_first_search
>>> gr = graph()
>>> # Add nodes
>>> gr.add_nodes(['X','Y','Z'])
>>> gr.add_nodes(['A','B','C'])
>>> # Add edges
>>> gr.add_edge(('X','Y'))
>>> gr.add_edge(('X','Z'))
>>> gr.add_edge(('A','B'))
>>> gr.add_edge(('A','C'))
>>> gr.add_edge(('Y','B'))
>>> # Depth first search rooted on node X
>>> st, pre, post = depth_first_search(gr, root='X')
>>> # Print the spanning tree
>>> print st
{'A': 'B', 'C': 'A', 'B': 'Y', 'Y': 'X', 'X': None, 'Z': 'X'}

Submodules

Variables
  __package__ = None
python-graph-1.8.2/docs/identifier-index.html0000644000175000017500000016734612016145552020265 0ustar morphmorph Identifier Index
 

Identifier Index

[ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ ]

A

B

C

D

E

F

G

H

I

L

M

N

O

P

R

S

T

U

W

_



python-graph-1.8.2/docs/help.html0000644000175000017500000002521012016145552015745 0ustar morphmorph Help
 

API Documentation

This document contains the API (Application Programming Interface) documentation for python-graph. Documentation for the Python objects defined by the project is divided into separate pages for each package, module, and class. The API documentation also includes two pages containing information about the project as a whole: a trees page, and an index page.

Object Documentation

Each Package Documentation page contains:

  • A description of the package.
  • A list of the modules and sub-packages contained by the package.
  • A summary of the classes defined by the package.
  • A summary of the functions defined by the package.
  • A summary of the variables defined by the package.
  • A detailed description of each function defined by the package.
  • A detailed description of each variable defined by the package.

Each Module Documentation page contains:

  • A description of the module.
  • A summary of the classes defined by the module.
  • A summary of the functions defined by the module.
  • A summary of the variables defined by the module.
  • A detailed description of each function defined by the module.
  • A detailed description of each variable defined by the module.

Each Class Documentation page contains:

  • A class inheritance diagram.
  • A list of known subclasses.
  • A description of the class.
  • A summary of the methods defined by the class.
  • A summary of the instance variables defined by the class.
  • A summary of the class (static) variables defined by the class.
  • A detailed description of each method defined by the class.
  • A detailed description of each instance variable defined by the class.
  • A detailed description of each class (static) variable defined by the class.

Project Documentation

The Trees page contains the module and class hierarchies:

  • The module hierarchy lists every package and module, with modules grouped into packages. At the top level, and within each package, modules and sub-packages are listed alphabetically.
  • The class hierarchy lists every class, grouped by base class. If a class has more than one base class, then it will be listed under each base class. At the top level, and under each base class, classes are listed alphabetically.

The Index page contains indices of terms and identifiers:

  • The term index lists every term indexed by any object's documentation. For each term, the index provides links to each place where the term is indexed.
  • The identifier index lists the (short) name of every package, module, class, method, function, variable, and parameter. For each identifier, the index provides a short description, and a link to its documentation.

The Table of Contents

The table of contents occupies the two frames on the left side of the window. The upper-left frame displays the project contents, and the lower-left frame displays the module contents:

Project
Contents
...
API
Documentation
Frame


Module
Contents
 
...
 

The project contents frame contains a list of all packages and modules that are defined by the project. Clicking on an entry will display its contents in the module contents frame. Clicking on a special entry, labeled "Everything," will display the contents of the entire project.

The module contents frame contains a list of every submodule, class, type, exception, function, and variable defined by a module or package. Clicking on an entry will display its documentation in the API documentation frame. Clicking on the name of the module, at the top of the frame, will display the documentation for the module itself.

The "frames" and "no frames" buttons below the top navigation bar can be used to control whether the table of contents is displayed or not.

The Navigation Bar

A navigation bar is located at the top and bottom of every page. It indicates what type of page you are currently viewing, and allows you to go to related pages. The following table describes the labels on the navigation bar. Note that not some labels (such as [Parent]) are not displayed on all pages.

Label Highlighted when... Links to...
[Parent] (never highlighted) the parent of the current package
[Package] viewing a package the package containing the current object
[Module] viewing a module the module containing the current object
[Class] viewing a class the class containing the current object
[Trees] viewing the trees page the trees page
[Index] viewing the index page the index page
[Help] viewing the help page the help page

The "show private" and "hide private" buttons below the top navigation bar can be used to control whether documentation for private objects is displayed. Private objects are usually defined as objects whose (short) names begin with a single underscore, but do not end with an underscore. For example, "_x", "__pprint", and "epydoc.epytext._tokenize" are private objects; but "re.sub", "__init__", and "type_" are not. However, if a module defines the "__all__" variable, then its contents are used to decide which objects are private.

A timestamp below the bottom navigation bar indicates when each page was last updated.

python-graph-1.8.2/docs/epydoc.js0000644000175000017500000002452512016145552015760 0ustar morphmorphfunction toggle_private() { // Search for any private/public links on this page. Store // their old text in "cmd," so we will know what action to // take; and change their text to the opposite action. var cmd = "?"; var elts = document.getElementsByTagName("a"); for(var i=0; i...
"; elt.innerHTML = s; } } function toggle(id) { elt = document.getElementById(id+"-toggle"); if (elt.innerHTML == "-") collapse(id); else expand(id); return false; } function highlight(id) { var elt = document.getElementById(id+"-def"); if (elt) elt.className = "py-highlight-hdr"; var elt = document.getElementById(id+"-expanded"); if (elt) elt.className = "py-highlight"; var elt = document.getElementById(id+"-collapsed"); if (elt) elt.className = "py-highlight"; } function num_lines(s) { var n = 1; var pos = s.indexOf("\n"); while ( pos > 0) { n += 1; pos = s.indexOf("\n", pos+1); } return n; } // Collapse all blocks that mave more than `min_lines` lines. function collapse_all(min_lines) { var elts = document.getElementsByTagName("div"); for (var i=0; i 0) if (elt.id.substring(split, elt.id.length) == "-expanded") if (num_lines(elt.innerHTML) > min_lines) collapse(elt.id.substring(0, split)); } } function expandto(href) { var start = href.indexOf("#")+1; if (start != 0 && start != href.length) { if (href.substring(start, href.length) != "-") { collapse_all(4); pos = href.indexOf(".", start); while (pos != -1) { var id = href.substring(start, pos); expand(id); pos = href.indexOf(".", pos+1); } var id = href.substring(start, href.length); expand(id); highlight(id); } } } function kill_doclink(id) { var parent = document.getElementById(id); parent.removeChild(parent.childNodes.item(0)); } function auto_kill_doclink(ev) { if (!ev) var ev = window.event; if (!this.contains(ev.toElement)) { var parent = document.getElementById(this.parentID); parent.removeChild(parent.childNodes.item(0)); } } function doclink(id, name, targets_id) { var elt = document.getElementById(id); // If we already opened the box, then destroy it. // (This case should never occur, but leave it in just in case.) if (elt.childNodes.length > 1) { elt.removeChild(elt.childNodes.item(0)); } else { // The outer box: relative + inline positioning. var box1 = document.createElement("div"); box1.style.position = "relative"; box1.style.display = "inline"; box1.style.top = 0; box1.style.left = 0; // A shadow for fun var shadow = document.createElement("div"); shadow.style.position = "absolute"; shadow.style.left = "-1.3em"; shadow.style.top = "-1.3em"; shadow.style.background = "#404040"; // The inner box: absolute positioning. var box2 = document.createElement("div"); box2.style.position = "relative"; box2.style.border = "1px solid #a0a0a0"; box2.style.left = "-.2em"; box2.style.top = "-.2em"; box2.style.background = "white"; box2.style.padding = ".3em .4em .3em .4em"; box2.style.fontStyle = "normal"; box2.onmouseout=auto_kill_doclink; box2.parentID = id; // Get the targets var targets_elt = document.getElementById(targets_id); var targets = targets_elt.getAttribute("targets"); var links = ""; target_list = targets.split(","); for (var i=0; i" + target[0] + ""; } // Put it all together. elt.insertBefore(box1, elt.childNodes.item(0)); //box1.appendChild(box2); box1.appendChild(shadow); shadow.appendChild(box2); box2.innerHTML = "Which "+name+" do you want to see documentation for?" + ""; } return false; } function get_anchor() { var href = location.href; var start = href.indexOf("#")+1; if ((start != 0) && (start != href.length)) return href.substring(start, href.length); } function redirect_url(dottedName) { // Scan through each element of the "pages" list, and check // if "name" matches with any of them. for (var i=0; i-m" or "-c"; // extract the portion & compare it to dottedName. var pagename = pages[i].substring(0, pages[i].length-2); if (pagename == dottedName.substring(0,pagename.length)) { // We've found a page that matches `dottedName`; // construct its URL, using leftover `dottedName` // content to form an anchor. var pagetype = pages[i].charAt(pages[i].length-1); var url = pagename + ((pagetype=="m")?"-module.html": "-class.html"); if (dottedName.length > pagename.length) url += "#" + dottedName.substring(pagename.length+1, dottedName.length); return url; } } } python-graph-1.8.2/docs/epydoc.css0000644000175000017500000003712212016145552016131 0ustar morphmorph /* Epydoc CSS Stylesheet * * This stylesheet can be used to customize the appearance of epydoc's * HTML output. * */ /* Default Colors & Styles * - Set the default foreground & background color with 'body'; and * link colors with 'a:link' and 'a:visited'. * - Use bold for decision list terms. * - The heading styles defined here are used for headings *within* * docstring descriptions. All headings used by epydoc itself use * either class='epydoc' or class='toc' (CSS styles for both * defined below). */ body { background: #ffffff; color: #000000; } p { margin-top: 0.5em; margin-bottom: 0.5em; } a:link { color: #3f3eb0; } a:visited { color: #3e75b0; } dt { font-weight: bold; } h1 { font-size: +140%; font-weight: bold; } h2 { font-size: +125%; font-style: italic; font-weight: bold; } h3 { font-size: +110%; font-weight: normal; } code { font-size: 100%; } /* N.B.: class, not pseudoclass */ a.link { font-family: monospace; } /* Page Header & Footer * - The standard page header consists of a navigation bar (with * pointers to standard pages such as 'home' and 'trees'); a * breadcrumbs list, which can be used to navigate to containing * classes or modules; options links, to show/hide private * variables and to show/hide frames; and a page title (using *

). The page title may be followed by a link to the * corresponding source code (using 'span.codelink'). * - The footer consists of a navigation bar, a timestamp, and a * pointer to epydoc's homepage. */ h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; } h2.epydoc { font-size: +130%; font-weight: bold; } h3.epydoc { font-size: +115%; font-weight: bold; margin-top: 0.2em; } td h3.epydoc { font-size: +115%; font-weight: bold; margin-bottom: 0; } table.navbar { background: #d5dce3; color: #000000; border: 0px groove #c0d0d0; } table.navbar table { color: #000000; } th.navbar-select { background: #3e75b0; color: #d5dce3; } table.navbar a { text-decoration: none; } table.navbar a:link { color: #3e75b0; } table.navbar a:visited { color: #3e75b0; } span.breadcrumbs { font-size: 85%; font-weight: bold; } span.options { font-size: 70%; } span.codelink { font-size: 85%; } td.footer { font-size: 85%; } /* Table Headers * - Each summary table and details section begins with a 'header' * row. This row contains a section title (marked by * 'span.table-header') as well as a show/hide private link * (marked by 'span.options', defined above). * - Summary tables that contain user-defined groups mark those * groups using 'group header' rows. */ td.table-header { background: #d5dce3; color: #000000; border: 1px solid #608090; } td.table-header table { color: #000000; } td.table-header table a:link { color: #0000ff; } td.table-header table a:visited { color: #204080; } span.table-header { font-size: 120%; font-weight: bold; } th.group-header { background: #c0e0f8; color: #000000; text-align: left; font-style: italic; font-size: 115%; border: 1px solid #608090; } /* Summary Tables (functions, variables, etc) * - Each object is described by a single row of the table with * two cells. The left cell gives the object's type, and is * marked with 'code.summary-type'. The right cell gives the * object's name and a summary description. * - CSS styles for the table's header and group headers are * defined above, under 'Table Headers' */ table.summary { border-collapse: collapse; background: #ffffff; color: #000000; border: 1px solid #608090; margin-bottom: 0.5em; } td.summary { border: 1px solid #608090; } code.summary-type { font-size: 85%; } table.summary a:link { color: #3f3eb0; } table.summary a:visited { color: #3e75b0; } /* Details Tables (functions, variables, etc) * - Each object is described in its own div. * - A single-row summary table w/ table-header is used as * a header for each details section (CSS style for table-header * is defined above, under 'Table Headers'). */ table.details { border-collapse: collapse; background: #fafafa; color: #000000; border: 1px solid #cccccc; margin: .2em 0 0 0; } table.details table { color: #000000; } table.details a:link { color: #3f3eb0; } table.details a:visited { color: #3e75b0; } /* Fields */ dl.fields { margin-left: 2em; margin-top: 1em; margin-bottom: 1em; } dl.fields dd ul { margin-left: 0em; padding-left: 0em; } dl.fields dd ul li ul { margin-left: 2em; padding-left: 0em; } div.fields { margin-left: 2em; } div.fields p { margin-bottom: 0.5em; } /* Index tables (identifier index, term index, etc) * - link-index is used for indices containing lists of links * (namely, the identifier index & term index). * - index-where is used in link indices for the text indicating * the container/source for each link. * - metadata-index is used for indices containing metadata * extracted from fields (namely, the bug index & todo index). */ table.link-index { border-collapse: collapse; background: #fafafa; color: #000000; border: 1px solid #cccccc; } td.link-index { border-width: 0px; } table.link-index a:link { color: #3f3eb0; } table.link-index a:visited { color: #3e75b0; } span.index-where { font-size: 70%; } table.metadata-index { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin: .2em 0 0 0; } td.metadata-index { border-width: 1px; border-style: solid; } table.metadata-index a:link { color: #0000ff; } table.metadata-index a:visited { color: #204080; } /* Function signatures * - sig* is used for the signature in the details section. * - .summary-sig* is used for the signature in the summary * table, and when listing property accessor functions. * */ .sig-name { color: #006080; } .sig-arg { color: #008060; } .sig-default { color: #602000; } .summary-sig { font-family: monospace; } .summary-sig-name { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:link { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:visited { color: #006080; font-weight: bold; } .summary-sig-arg { color: #006040; } .summary-sig-default { color: #501800; } /* Subclass list */ ul.subclass-list { display: inline; } ul.subclass-list li { display: inline; } /* To render variables, classes etc. like functions */ table.summary .summary-name { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:link { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:visited { color: #006080; font-weight: bold; font-family: monospace; } /* Variable values * - In the 'variable details' sections, each varaible's value is * listed in a 'pre.variable' box. The width of this box is * restricted to 80 chars; if the value's repr is longer than * this it will be wrapped, using a backslash marked with * class 'variable-linewrap'. If the value's repr is longer * than 3 lines, the rest will be ellided; and an ellipsis * marker ('...' marked with 'variable-ellipsis') will be used. * - If the value is a string, its quote marks will be marked * with 'variable-quote'. * - If the variable is a regexp, it is syntax-highlighted using * the re* CSS classes. */ pre.variable { padding: .5em; margin: 0; background: #dce4ec; color: #000000; border: 1px solid #708890; } .variable-linewrap { color: #604000; font-weight: bold; } .variable-ellipsis { color: #604000; font-weight: bold; } .variable-quote { color: #604000; font-weight: bold; } .variable-group { color: #008000; font-weight: bold; } .variable-op { color: #604000; font-weight: bold; } .variable-string { color: #006030; } .variable-unknown { color: #a00000; font-weight: bold; } .re { color: #000000; } .re-char { color: #006030; } .re-op { color: #600000; } .re-group { color: #003060; } .re-ref { color: #404040; } /* Base tree * - Used by class pages to display the base class hierarchy. */ pre.base-tree { font-size: 80%; margin: 0; } /* Frames-based table of contents headers * - Consists of two frames: one for selecting modules; and * the other listing the contents of the selected module. * - h1.toc is used for each frame's heading * - h2.toc is used for subheadings within each frame. */ h1.toc { text-align: center; font-size: 105%; margin: 0; font-weight: bold; padding: 0; } h2.toc { font-size: 100%; font-weight: bold; margin: 0.5em 0 0 -0.3em; } /* Syntax Highlighting for Source Code * - doctest examples are displayed in a 'pre.py-doctest' block. * If the example is in a details table entry, then it will use * the colors specified by the 'table pre.py-doctest' line. * - Source code listings are displayed in a 'pre.py-src' block. * Each line is marked with 'span.py-line' (used to draw a line * down the left margin, separating the code from the line * numbers). Line numbers are displayed with 'span.py-lineno'. * The expand/collapse block toggle button is displayed with * 'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not * modify the font size of the text.) * - If a source code page is opened with an anchor, then the * corresponding code block will be highlighted. The code * block's header is highlighted with 'py-highlight-hdr'; and * the code block's body is highlighted with 'py-highlight'. * - The remaining py-* classes are used to perform syntax * highlighting (py-string for string literals, py-name for names, * etc.) */ pre.py-doctest { padding: .5em; margin: 1em; background: #fafafa; color: #000000; border: 1px solid #cccccc; } table pre.py-doctest { background: #dce4ec; color: #000000; } pre.py-src { border: 2px solid #000000; background: #f0f0f0; color: #000000; } .py-line { border-left: 2px solid #000000; margin-left: .2em; padding-left: .4em; } .py-lineno { font-style: italic; font-size: 90%; padding-left: .5em; } a.py-toggle { text-decoration: none; } div.py-highlight-hdr { border-top: 2px solid #000000; border-bottom: 2px solid #000000; background: #d8e8e8; } div.py-highlight { border-bottom: 2px solid #000000; background: #d0e0e0; } .py-prompt { color: #005050; font-weight: bold;} .py-more { color: #005050; font-weight: bold;} .py-string { color: #006030; } .py-comment { color: #003060; } .py-keyword { color: #600000; } .py-output { color: #404040; } .py-name { color: #000050; } .py-name:link { color: #000050 !important; } .py-name:visited { color: #000050 !important; } .py-number { color: #005000; } .py-defname { color: #000060; font-weight: bold; } .py-def-name { color: #000060; font-weight: bold; } .py-base-class { color: #000060; } .py-param { color: #000060; } .py-docstring { color: #006030; } .py-decorator { color: #804020; } /* Use this if you don't want links to names underlined: */ /*a.py-name { text-decoration: none; }*/ /* Graphs & Diagrams * - These CSS styles are used for graphs & diagrams generated using * Graphviz dot. 'img.graph-without-title' is used for bare * diagrams (to remove the border created by making the image * clickable). */ img.graph-without-title { border: none; } img.graph-with-title { border: 1px solid #000000; } span.graph-title { font-weight: bold; } span.graph-caption { } /* General-purpose classes * - 'p.indent-wrapped-lines' defines a paragraph whose first line * is not indented, but whose subsequent lines are. * - The 'nomargin-top' class is used to remove the top margin (e.g. * from lists). The 'nomargin' class is used to remove both the * top and bottom margin (but not the left or right margin -- * for lists, that would cause the bullets to disappear.) */ p.indent-wrapped-lines { padding: 0 0 0 7em; text-indent: -7em; margin: 0; } .nomargin-top { margin-top: 0; } .nomargin { margin-top: 0; margin-bottom: 0; } /* HTML Log */ div.log-block { padding: 0; margin: .5em 0 .5em 0; background: #e8f0f8; color: #000000; border: 1px solid #000000; } div.log-error { padding: .1em .3em .1em .3em; margin: 4px; background: #ffb0b0; color: #000000; border: 1px solid #000000; } div.log-warning { padding: .1em .3em .1em .3em; margin: 4px; background: #ffffb0; color: #000000; border: 1px solid #000000; } div.log-info { padding: .1em .3em .1em .3em; margin: 4px; background: #b0ffb0; color: #000000; border: 1px solid #000000; } h2.log-hdr { background: #70b0ff; color: #000000; margin: 0; padding: 0em 0.5em 0em 0.5em; border-bottom: 1px solid #000000; font-size: 110%; } p.log { font-weight: bold; margin: .5em 0 .5em 0; } tr.opt-changed { color: #000000; font-weight: bold; } tr.opt-default { color: #606060; } pre.log { margin: 0; padding: 0; padding-left: 1em; } python-graph-1.8.2/docs/crarr.png0000644000175000017500000000052412016145552015747 0ustar morphmorph‰PNG  IHDR e’E,tEXtCreation TimeTue 22 Aug 2006 00:43:10 -0500` XtIMEΦ)Σ}Φ pHYsΒΒnΠu>gAMA± όaEPLTEΝΓ°ΧΟΐ€f4sW αΫЊrD`@bCάΥΘιδά–X{`,―Ÿ€lN‡o@υσπͺ™xdEπν螊dΠΖ΄”~TΦwΕvtRNS@ζΨfMIDATxΪc`@ΌμΌ0&+š—Šˆ°»(’ˆ€ ;; /πEXωΨ‘?Π n ƒͺ†— b;'ͺ+˜˜YΠ#œ(r<£"IENDB`‚python-graph-1.8.2/docs/class_hierarchy_for_radius.gif0000644000175000017500000000065712016145554022210 0ustar morphmorphGIF89aH%γώΣΣΣΠΠώ?44ΏœœŸ‚‚hh_NN‹qqίΆΆ!ω,H%ώ0ΘI«½8λΝ»`(Ž€&œhͺlλΎξΟtmΛvηΈ@όΐ pH,ATΙl:J κI­"£•©uΛ%`)ΪΨω„Ηhθi™nΛ’sz!844< G|  zkR'UxC? i{}C *y  ’€’‹E”‡W(§x£* ^>^ Ήy¨y―…Y±F¨u‘ ‹ Ώ ‹ΤΆ¨’· Λ ’jlFƒ'‹ ¦‹η‚ΎΐwΥ)ΰoΗ`ΙEtτHh$€?ƒΐ:₯’—€Žƒ9κ₯‘jgι¦fHΚι§Fx κ¨AˆJκ©<˜Šκͺ7¨Κκ«2@Ζ¬΄Φjλ­ΈζZ¬6DΒλ―½+¬Ύkl Ε«l…Λ6 C²Ξ: m΄ΛώNKν±Φ^;lΆΪΛm·Ό~ ξ«βŽ»jΉζžŠnΊ£Λξ§ξΎ»iΌς:Jo½Žά‹o"ϊξ{HΏώpΐ} Lπ\GΒ ΏΑpÏ@l‚WlρΕV$ρ°ΔrhΜ±Η‰~ςΘ"±±"%ΓrΚCœœΛ*“ŒΖ+²l2Ν8Έ H(±ΕrΚφ €w¬œ‚51 B‘ΫΣh ΣTΓL₯»ωάτ~ί}ΒLδh‘: iOjτGLƒ―΄§> QB^Tΰ€€(KuQy£{ώT[8©0ΆΜ˜βTΫ·E˜₯ͺnό㘳91XfΌcσ¨G<Άc€ € Ð2υ‘X‡œW"-eΘEΚΡ‘ω‚d$%Ι/JV’Βd&5)0Nv“e(E‰0R–” Ce*Uι0VΆ•ƒ%)Λ‰Υς ΄Ό%ΚtΉ„\ς—„€0‡IL‹9—–8&2e‘ΜeΝΞ|$²’ωΜiR³UΝΌfΦ ιœε`!OάΑgrΑ9›!YΐμŒω|¦ΆœN6Η δΙŠΓ•*›(PΪ τ‰ «ΩΟi5°K‰¨Q(e`Yr:(J΄"ΓpγJψ”ΰΦ4"·―”kΙ›ώΩ<¨Ώ%œ2JPΆRΈ39NτΔB†Ρ‘“z"&ΓXiΤΰFΉx ¦όΡ N%ΚΣΒB09ή‹Η•Π1.,­{œέt'9”š‡‰©ιRϊ±ΉΠm$9BͺκPyRŽ(4ΐs›ΒhŽΔMό.wJ]eΞΌΧΑ³xaνΆ“ΣwD°%ˆα‰hθρ–‘βΥ™`E:R7R vA_kbh7ΓΖ6ΗwΝSMάN#=χP/Φ« ο‘΅‘.yQNΤG"μP8έH«)L£μΞgΚlL˜Όžϊ#½Q[xθWΠ 6=šq{€ϊ–μ€"m‹Ρ ό‚˜ω _ώλΑΖH·gtΑg>3\šŒΣΆdEAO:Θ*‘%-ί†Β­ΘC ‚αˆb$†¨Ο!€₯―‡(œβ(³™]οlΚͺΕΪι†A|lˆ)κ©«Uٟ8!#–)‰ΰTR@φ—3a¦*Κ  >‘3w•‰ T˜ήΥOD,°5ΕNN’Σeτ䍋°FGT›Οϊ1 μΨ!ΌFFrΗ’ƒ3YΘk(¦”§Lε-μ+΅Δ²,΅ K.»Λ¬³*ŌJ2›Μ€D³(Υ J6λψΙη„σάμc9'ΣΞoΔ33υ,M>cΣΟ{΄½MBΪΠ±Bτ‘ώ esUωѐžς θ,²lQϊc–Ft¦ ½iBwZПt¨yζڜ%%»3πζ³Μ‰ΘD“¨^ΖΪ‚ΠΖΪυάκœ'έ~φzjΌπη^Jƒ¨eδi,@ΥN 4c;”ΨGžq8(κ5ι^TlOΡh)8κΩ”ΆM‘Ή HnLŒ’"ρ£%….8‚Ž8ΟΉE6NqΚ7Ϋ΄ΆVΙO ԟ 5sKν`9γ4–€ ₯IuSR‘ΝYw©Ϋxΐ'V―‚΅/Œ oUpΦΘΈ₯wυ-έ‡]wΨOvqΥ,%σXΐ6$΄c\„ϋ„˜c­"‡ήέ{XΕVΙΜZ„ψfγώ΄X΄B[΄¬φH›΄J«!;python-graph-1.8.2/docs/class_hierarchy_for_negativewe.gif0000644000175000017500000001023612016145554023051 0ustar morphmorphGIF89aΘ=„ώΣΣΣ___???ίίߟŸŸΏΏΏΓΓΓ‹‹‹ΠΠώίΆΆΏœœ?44_NNŸ‚‚hh§ˆˆuu!ω,Θ=ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙ| žΠ¨tJ­Z―Ψ¬vΛνzΏ`AJά,›Ο"ςIn»‰μRόM―ηζ#Ό}Οwι}‚ƒyc„‡ˆ…(‰mŒI=R wSD“•:g™; T7¨—?’£₯; +”ͺ0΅·)¨¦Έ Ά5€ΎΆͺ Ά *Ίͺ€6ΠΏ&½#ΏΑΓ4³)QΤO ΆΞάΝ"βPΤ" ΆΤ P βͺRΏΚ”"ΠΞHδ ˆͺ@€IQ*ύc°έjωˆΙ`0†μƍˆ'`^½χδ‹²Oœ'ΰώN*p`%°Žβœ9μ‹₯Λ™ˆΕ$¦ ΜX8‰¨„κ€[QX–(`h¦+[Δiπ%3 F½)E'Ε4=»ύΜtEJ;D˜V4„ ΏͺUλ,_&š’Š wχkLV\ΫΥn ΐζ”wl‰‘zϋ$ncƒbEΖ’y°Ÿή—}4΄₯OςOLˆJ"=ΑύŒ5Uσ·cΖηH’`*"5ROl FϊDΥ”fύN€ΆΌ rΧ9_ΙΆ5’φ»(IŸ˜€T Uθˆƒέ}o,VR3ι^σ₯ΔnάŒ”hήΧxξ?t“„ό5Ω&Œ$x‰|$πώυTqΧ–K―₯QUv₯₯@|τ`W\Ξ•”QQ\ψHρS2Ά!#^UΘ…APU¦β2ΎψΟcVm8j–5"‰šEqβ‚οPΈ† @€TDΡΔ&ڈ£€qΠγ ,qv#%—™'™0KvfΠ…Sf„ M€‰K’a^Ψίd Β(₯)IfGVJœ3ZŽ΄Ξ\ξ±pVΩ8BD‘H )τ£J(ϊC>ƒ9κ₯‘jgι¦fHΚι§Fx κ¨AˆJκ©<˜Šκͺ7¨Κκ«2@Ζ¬΄Φjλ­ΈζZ¬6DΒλ―½+¬Ύkl Ε«l…Λ6 C²Ξ: m΄ΛώNKν±Φ^;lΆΪΛm·Ό~ ξ«βŽ»jΉζžŠnΊ£Λξ§ξΎ»iΌς:Jo½Žά‹o"ϊξ{HΏώpΐ} Lπ\GΒ ΏΑpÏ@l‚WlρΕV$ρ°ΔrhΜ±Η‰~ςΘ"±±"%ΓrΚCœœΛ*“ŒΖ+²l2Ν8Έ H(±ΕrΚφ €w¬œ‚51 B‘ΫΣh ΣTΓL₯»ωάτ~ί}ΒLδh‘: iOjτGLƒ―΄§> QB^Tΰ€€(KuQy£{ώT[8©0ΆΜ˜βTΫ·E˜₯ͺnό㘳91XfΌcσ¨G<Άc€ € Ð2υ‘X‡œW"-eΘEΚΡ‘ω‚d$%Ι/JV’Βd&5)0Nv“e(E‰0R–” Ce*Uι0VΆ•ƒ%)Λ‰Υς ΄Ό%ΚtΉ„\ς—„€0‡IL‹9—–8&2e‘ΜeΝΞ|$²’ωΜiR³UΝΌfΦ ιœε`!OάΑgrΑ9›!YΐμŒω|¦ΆœN6Η δΙŠΓ•*›(PΪ τ‰ «ΩΟi5°K‰¨Q(e`Yr:(J΄"ΓpγJψ”ΰΦ4"·―”kΙ›ώΩ<¨Ώ%œ2JPΆRΈ39NτΔB†Ρ‘“z"&ΓXiΤΰFΉx ¦όΡ N%ΚΣΒB09ή‹Η•Π1.,­{œέt'9”š‡‰©ιRϊ±ΉΠm$9BͺκPyRŽ(4ΐs›ΒhŽΔMό.wJ]eΞΌΧΑ³xaνΆ“ΣwD°%ˆα‰hθρ–‘βΥ™`E:R7R vA_kbh7ΓΖ6ΗwΝSMάN#=χP/Φ« ο‘΅‘.yQNΤG"μP8έH«)L£μΞgΚlL˜Όžϊ#½Q[xθWΠ 6=šq{€ϊ–μ€"m‹Ρ ό‚˜ω _ώλΑΖH·gtΑg>3\šŒΣΆdEAO:Θ*‘%-ί†Β­ΘC ‚αˆb$†¨Ο!€₯―‡(œβ(³™]οlΚͺΕΪι†A|lˆ)κ©«Uٟ8!#–)‰ΰTR@φ—3a¦*Κ  >‘3w•‰ T˜ήΥOD,°5ΕNN’Σeτ䍋°FGT›Οϊ1 μΨ!ΌFFrΗ’ƒ3YΘk(¦”§Lε-μ+΅Δ²,΅ K.»Λ¬³*ŌJ2›Μ€D³(Υ J6λψΙη„σάμc9'ΣΞoΔ33υ,M>cΣΟ{΄½MBΪΠ±Bτ‘ώ esUωѐžς θ,²lQϊc–Ft¦ ½iBwZПt¨yζڜ%%»3πζ³Μ‰ΘD“¨^ΖΪ‚ΠΖΪυάκœ'έ~φzjΌπη^Jƒ¨eδi,@ΥN 4c;”ΨGžq8(κ5ι^TlOΡh)8κΩ”ΆM‘Ή HnLŒ’"ρ£%….8‚Ž8ΟΉE6NqΚ7Ϋ΄ΆVΙO ԟ 5sKν`9γ4–€ ₯IuSR‘ΝYw©Ϋxΐ'V―‚΅/Œ oUpΦΘΈ₯wυ-έ‡]wΨOvqΥ,%σXΐ6$΄c\„ϋ„˜c­"‡ήέ{XΕVΙΜZ„ψfγώG;―@u/…65'7»ώbX΄Σs(·XΟ#ƒπΒ8!ηƒ Τ![ρuΝ…]ϋ•uύ έσZ¦v55v–*Œπ„Ε‘?72&‡\V˜?_! X±0vΫ%pηŒώΧ‡+`8Α‰0d‹%"d5’!%D §§]€z hŒ*'”γΑ #β|Ί(U4|ΔΐΦnΜ§ Ή(Ϋx‰;€ήBƒ4°†aψ+9(€4°%Pb,ω€8θ “‘XƒΉ‘EΨ‚!y0>%˜’Wπfx’…τ.Y21Yi0Y“-i“ˆ“!¨“8“+x“@™“AΉ“CΩ“<)>I’0¨’LΩ”΅eώN•Rie3•Vy•¬†’°•\Ω•^ω•`–b9–dY–fy–h™–jΉ–i PΙ–p—r9—tY—v –nY•p—|Ω—~ω—€9–yΉY˜†y˜ˆY–ƒ9Y{™˜Žω˜Ι—‹©•‘Y™–y™ŠΉ+„‰™œΩ™—9™„Q–π°•£)wyši9P[)O`š``©ša0d°)ii›aI€ š\U–Έ™›[I­9—ͺɜ‰–М£›ΐš–Π)–Μ™]i›ΣœgΉ·9΄ω—Ζ ežΙš₯9ΰ›δɚΊΙ•Ό9ώŸPš€›ΡIžb)ŸτιΣιšΊ—£I›ϊ›\  φΩ•Ψ ›χιŸΐœ0Ÿήi–πΉ• JžΜyŸ9Ÿ°‘™‰μI–z‘›Π›O ›¬ωΣ9Υ ¨ιžΰ’Έ‰šڜ0ͺœΫٚ±9€χι’Χ 5Ϊ’R::ŸόY‘@=Ί•FJ ϊYšJŠ€Κ’^ ›P’bZ’3 ΐY¦&Ϊ•λic9Ÿ£©›³ΙœγI§Έ9žڜψι›―)₯› κJ§@§š›ΜY`%:›…:›[›w yκšObκ€p§΅ ©€΄ ©„ώj¨N*ž‘ Ιω0›\ڜQ0₯^Ω¦)–ͺ)¦Ή™©0›ͺ©‚J0ŸΡι©|š«΄9­ΚŸŠ› ¨Iš­‰«ΒŠš»*¦Wκ€ΐ ©MŠ—Εκ§Μω›Υ§ΌJ¬§Ί™œ₯iKʟŠb)«»ΩœΣ ›ξ‰£pΊ•σy¨O ‘‚Κ§ζι’Γ:¨yš,ϊ°™«R€šΫY―‹Ί—ζy―ͺ™­*Ρ §|Š«Λιͺ۟ΓΪ•ζΩ°³*¦ζٚɘd™₯7zŽΪ• ¬9ž¬j­‡j ~ϊ₯¬ œ  ² ©ۚ7λ•Ί²-›ϋаπϊ²Jž+ œRϊ’ώ Ÿ=Λ±z ‘3+΄ ›†Ί«"‹’n–JZͺy γ€Ήy₯ϊ₯˜*δžΡΉ°`Kž4:J+žiŠΆ₯ Ίy―‡*£,z£¨Κ•3š€Q€šJ:Ÿm»€Rp·³Š·†Ϋ·Š›΅oω¦³j¨Lk6*¨ϊ‰NjΣ™žΚ©›ž¦ ›”  OΰΆΚ)¨’[ΉβjΉΎ‰Ή:›₯ΫŸ½ΉŸ]žδΙ›³¬ι9ΉͺKΈQ:»Ί‚:£΄+ΌŽ«—Ω΅ž)–Κ—!»Ό‚9²”I—M’Πλ•Υ{Ίq Ώ ΊΧ{Ό›I—,›―kϋ½ΓKΎtΩ­8kΎ_ιμϋΎπ»–ξΏτ[+ΏΓ)½‘iΏϊ»Ώσ»Ώώ Ώ²Š•<•P9ΐά”|ΐ L‚Ψΐόΐ";python-graph-1.8.2/docs/class_hierarchy_for_labeling.gif0000644000175000017500000000556212016145554022476 0ustar morphmorphGIF89a]]„ώΣΣΣ???ΏΏΏŸŸŸίίί___ΓΓΓ‹‹‹ΠΠώίΆΆ?44Ÿ‚‚hh_NNΏœœߟ§ˆˆ!ω,]]ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙl:ŸΠ¨tJ­Z―Ψ¬vΛνzΏIxL.›Οθ΄z»ίπΈ|ήeΫοψ|™Ξοϋ€,z„…†‚‰Š‹ŒOc‘’“”•–—˜™š’cŽžŸ ‘’+›¦§¨§£¬­―r₯©³΄©«°ΈΉΊ»K²΅Ώΐ•·ΌΔΕΖΗ1ΎΑΛΏΓΘΟΠΡΌΚΜΥ¨ΞΩΪۍΤΦί™Ψάγδεoή“—›κμςΥβζχψωQθ’—&°Ι@ƒυΔθ[Θ°!~‘(¨P!‚…u"E˜X‰ΒΕHΜθ d&‰πώ4ΩsΘ²₯KlΌP†ƒ‹.¦ά8ήƐ?%U\qŒΐ”–VΎ\Κ”iL&Ή›gF‚? :€IŒΖ2άa…pΰ%₯MΣͺΥQΌ¬Κ:ΈšQℍ$‘Ί-It+GΌ#Ώ’Lͺp­αΓl½b2θO N‘# lL&B„ξv »9Εp…‹­ ’D P3έНšX'<ΉkTœ$FΕ„–΄οί nDΝqW°7Ι`]έ9hf™eFΌΊυWΉn΄ 0*„ t,ΉBH[w£―Ν9‚ΔρgC_ŸOΏ›bpΦ‚ς–_ΏΏ>1α§ΙQs½£%ώ¨ΰ ˆInŽ™u Vha :˜…vθα#χi(’_~hβ‰Ed8"0½‘θβ‹4¨Έb--Βhγ*’γŽiΰθγ.π(δ@id C&©γ‘L6‚NF)ε>d`Ζ”XfIΔH"Ι₯–`†ωB•9’ς₯˜hfy&)ɐ™ζ›?Ί™Œ rΒiη…uΞPb kήιguyωCŸΊ‘9μι’†6:£<(*Δ•ŽVϊ €@Hz¦–vΊ₯MhΪ §ž–κ©iͺ©¬n*’Z±j«΄ΒZγ>sΌZλzΚE¬`θΚλ°^Byͺ"Β[j²ͺzΒ¬²vϊ ΰ(ΟώB;₯΄€kί­Φ2‰m"Ϊ‚Rm·ŽKGΈ¬˜K.}ߊ›Ίλo θNΣnΌ’έ‹]>σβϋ¨ΎΉΤ+Ν¬ώ.Dπ»Nυ[°Έ οkΨΑN*)ρΔW,$g¬ρΖvάΐρΗ ‡,²’)Ό Ι& |¨Ηλjͺς/sK3Ο\¨ΛqbΜ.Λδβμ£Ν6;TsΛ%ηΜσuCχ\τΟ:Ο—t·>γτΞ‚*‚Ι `€ p@Φ[χp€ ΈΠυΧZ‹Mφ˜MΓφc—MDάlWΓΫHΠέ…ή'π­…ίe^-ΰ„ˆnx„#ΰβ(ΞΈŽΩφ ’ΛΡx›[n7 ώ™Ρ9£›Pz§/}‚Ιgp€h}@ Δn@Ι ξ"t-wί°ΛBΧ ώϋΥΊΐ»ο)Όnϋμ)oό —›ν΅λΑύ ΅kΝϋ Μ£ΰΌπΡS>½ α|ωΕ―Νζηά_?Ύφ΄Ϋώ=ϋηΧού ι›0φό3ŸϋH ½rΟ~<^ ώ7<*0eͺKΦ‡Έd [K@χθ§Αυqc([Ι7‚€pe«`Ί&¬ q(Κ6ΔΠ} •W»ΎPƒ Sθ57”[Ε°CM‚βǐΑ Ξn„τϋ DhΕ°°p?Œώα 1ˆΔΨ)± ;όβ΅(Ζ#ΪЌ"XβυΗ§LPxœ’ͺΈ>,Bo‰\τΰδx€±…Ν…•s΅B6žPa4"GΔ8’±„4€ωFnΡ‘€$Ϋ8ΙNž‘ M$AΤP°Dέ y”L[Ά¦ΙYΊ.m„+@r[j’rtœBΖ¦ΛΔΞp¨ŒeΨ‚i%Κ±“e¦Χ^iΑc6“‰Κ΄$€ι8Ύ~&h₯•`iCYœ·άZ.wωΚ^ž³†·,¦5“YΞeF³™έœc9εYΈkκS“ΜC>S©Κ'²’ $g:έΉP_β’šΌt(<ρΙΖ¬ιΞ’ΪώΦΙK24€šΖμ'=ΚHRΤ›ͺt& 1ŠΡ`r΄ι₯MυλύήϊG―₯Uykέͺ[½W pŽhΕ&bΩΊXΈ‚U;•A¬μJU ΊO«–-j_E»ΤΆ€― Ό¬cΫιB¦žφ­μi±yVΓJ΄‹«μWνyΏΖ⎡ΧΣ­lΣZΫBή6±ύδ*l};Χ.₯₯"αώΔ;£Ζn dΕ?χRν±½L\?cΗ»ΨE.ΉΣ}₯3ΗV9DfΞΌΐ―yG^Μ½c¨ξ-ΫKΉχkjΟΝ©tσKΉξβΥΐ«₯!‚οWίπžwqιΥ/{7ΩίδΒw Ύ/„ Œ€ ΐ½ώ―AΓ)ΰ~FΈΐΧ=pŠŒΑ“ΐΏφυlΨ<ŒH3$5Δε»^g~ΈΒ‹»ptCγ·Ρ˜r6φoŽvܱԌ ΐo“Roœίέz;­€€―WnοˆΔ¨ςΰ.wΌΧύξ{Χ’ή“G6Ώ›–Βifx¬)ιυΗ+ώλ‘ϋΪ5Ο;GŸ½μœW^;οΜΔ{}εΏw –§weίUχGžάtm^εkϋΜήχmOϋοَvŒήΗ./ί―<΅Ο½„ΆC<μ_‰ωεΣώψ»^=ςρΪΦٟPψΑOΌλkyΤ{οΙγδ”eΜͺ`l‹ϋϋ›—ά†Ο σ_ύgων?χ+7‘6Πώ89X˜Z€Έ'kτo-:60V‡ΈhφG˜r'°΄6Έ"Θ 0Aδt‚'π.ΰ‚.°‚K2X0X>6yVΒAD}ρ3X7πƒ[„‰R=W@„Ψ@BΈJh=MȁθœυXQ˜O…9P…;w…(…-@m4Nƒ„Ώρ4Φ²J6`H“‚΅’†0†ց†Π‡/"‡€β†΄b‡.‚‡ΐA‡ΚΒ‡(β‡g¨‡­β2#“ˆŠΈˆ³ˆŽψˆlΰ18‰”X‰<²0˜˜‰šΈ‰œΨ‰žψ‰ ˆ!;python-graph-1.8.2/docs/class_hierarchy_for_invalidgra.gif0000644000175000017500000000757512016145554023047 0ustar morphmorphGIF89aΘ=„ώΣΣΣ___???ίίߟŸŸΏΏΏΓΓΓ‹‹‹ΠΠώΏœœ?44Ÿ‚‚_NNίΆΆhh‹qqߟ!ω,Θ=ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙ| žΠ¨tJ­Z―Ψ¬vΛνzΏ`AJά,›Ο"ςIn»‰μRόM―ηζ#Ό}Οwι}‚ƒyc„‡ˆ…(‰mŒI=R wSD“•:g™; T7¨—?’£₯; +”ͺ0΅·)¨¦Έ Ά5€ΎΆͺ Ά *Ίͺ€6ΠΏ&½#ΏΑΓ4³)QΤO ΆΞάΝ"βPΤ" ΆΤ P βͺRΏΚ”"ΠΞHδ ˆͺ@€IQ*ύc°έjωˆΙ`0†μƍˆ'`^½χδ‹²Oœ'ΰώN*p`%°Žβœ9μ‹₯Λ™ˆΕ$¦ ΜX8‰¨„κ€[QX–(`h¦+[Δiπ%3 F½)E'Ε4=»ύΜtEJ;D˜V4„ ΏͺUλ,_&š’Š wχkLV\ΫΥn ΐζ”wl‰‘zϋ$ncƒbEΖ’y°Ÿή—}4΄₯OςOLˆJ"=ΑύŒ5Uσ·cΖηH’`*"5ROl FϊDΥ”fύN€ΆΌ rΧ9_ΙΆ5’φ»(IŸ˜€T Uθˆƒέ}o,VR3ι^σ₯ΔnάŒ”hήΧxξ?t“„ό5Ω&Œ$x‰|$πώυTqΧ–K―₯QUv₯₯@|τ`W\Ξ•”QQ\ψHρS2Ά!#^UΘ…APU¦β2ΎψΟcVm8j–5"‰šEqβ‚οPΈ† @€TDΡΔ&ڈ£€qΠγ ,qv#%—™'™0KvfΠ…Sf„ M€‰K’a^Ψίd Β(₯)IfGVJœ3ZŽ΄Ξ\ξ±pVΩ8BD‘H )τ£J(ϊC>ƒ9κ₯‘jgι¦fHΚι§Fx κ¨AˆJκ©<˜Šκͺ7¨Κκ«2@Ζ¬΄Φjλ­ΈζZ¬6DΒλ―½+¬Ύkl Ε«l…Λ6 C²Ξ: m΄ΛώNKν±Φ^;lΆΪΛm·Ό~ ξ«βŽ»jΉζžŠnΊ£Λξ§ξΎ»iΌς:Jo½Žά‹o"ϊξ{HΏώpΐ} Lπ\GΒ ΏΑpÏ@l‚WlρΕV$ρ°ΔrhΜ±Η‰~ςΘ"±±"%ΓrΚCœœΛ*“ŒΖ+²l2Ν8Έ H(±ΕrΚφ €w¬œ‚51 B‘ΫΣh ΣTΓL₯»ωάτ~ί}ΒLδh‘: iOjτGLƒ―΄§> QB^Tΰ€€(KuQy£{ώT[8©0ΆΜ˜βTΫ·E˜₯ͺnό㘳91XfΌcσ¨G<Άc€ € Ð2υ‘X‡œW"-eΘEΚΡ‘ω‚d$%Ι/JV’Βd&5)0Nv“e(E‰0R–” Ce*Uι0VΆ•ƒ%)Λ‰Υς ΄Ό%ΚtΉ„\ς—„€0‡IL‹9—–8&2e‘ΜeΝΞ|$²’ωΜiR³UΝΌfΦ ιœε`!OάΑgrΑ9›!YΐμŒω|¦ΆœN6Η δΙŠΓ•*›(PΪ τ‰ «ΩΟi5°K‰¨Q(e`Yr:(J΄"ΓpγJψ”ΰΦ4"·―”kΙ›ώΩ<¨Ώ%œ2JPΆRΈ39NτΔB†Ρ‘“z"&ΓXiΤΰFΉx ¦όΡ N%ΚΣΒB09ή‹Η•Π1.,­{œέt'9”š‡‰©ιRϊ±ΉΠm$9BͺκPyRŽ(4ΐs›ΒhŽΔMό.wJ]eΞΌΧΑ³xaνΆ“ΣwD°%ˆα‰hθρ–‘βΥ™`E:R7R vA_kbh7ΓΖ6ΗwΝSMάN#=χP/Φ« ο‘΅‘.yQNΤG"μP8έH«)L£μΞgΚlL˜Όžϊ#½Q[xθWΠ 6=šq{€ϊ–μ€"m‹Ρ ό‚˜ω _ώλΑΖH·gtΑg>3\šŒΣΆdEAO:Θ*‘%-ί†Β­ΘC ‚αˆb$†¨Ο!€₯―‡(œβ(³™]οlΚͺΕΪι†A|lˆ)κ©«Uٟ8!#–)‰ΰTR@φ—3a¦*Κ  >‘3w•‰ T˜ήΥOD,°5ΕNN’Σeτ䍋°FGT›Οϊ1 μΨ!ΌFFrΗ’ƒ3YΘk(¦”§Lε-μ+΅Δ²,΅ K.»Λ¬³*ŌJ2›Μ€D³(Υ J6λψΙη„σάμc9'ΣΞoΔ33υ,M>cΣΟ{΄½MBΪΠ±Bτ‘ώ esUωѐžς θ,²lQϊc–Ft¦ ½iBwZПt¨yζڜ%%»3πζ³Μ‰ΘD“¨^ΖΪ‚ΠΖΪυάκœ'έ~φzjΌπη^Jƒ¨eδi,@ΥN 4c;”ΨGžq8(κ5ι^TlOΡh)8κΩ”ΆM‘Ή HnLŒ’"ρ£%….8‚Ž8ΟΉE6NqΚ7Ϋ΄ΆVΙO ԟ 5sKν`9γ4–€ ₯IuSR‘ΝYw©Ϋxΐ'V―‚΅/Œ oUpΦΘΈ₯wυ-έ‡]wΨOvqΥ,%σXΐ6$΄c\„ϋ„˜c­"‡ήέ{XΕVΙΜZ„ψfγώ–)hm/Β¨‚—]U‡˜ϋωi₯ˆΚΙ&mrDΰθv&q &ͺqtJβͺ΄΅JΗcœβΙ*¬_vθj…΄beλ™ΈΩ Ώ’ψicΦ6κ­qΒiJ†ώ~δζ’wJ֐&:ZžΣV€Χ΅’1J­ΆeF)‡pε‚›ιΌ΄‹ ²Kh=ΗΡ&š“|F§Vf™dgdθ3'U’R«šΎ50€€¨Š[ΑΟΐΏ?$ΑSΠο|_IΆ°\ ―Ά1Δ\’΄sl%yΞKγsοΑtPΎ$σλ―^Χ-Όž1ΫΈ¬ΌB[βσN8cJXa τ·274rŸ:]ζvͺJaS_QΝχ^Ν°Ξ&ΜcέΙ;apΒf·‰OŒŒi›<\’Ϊ%±νήsp˝5Όο*pBχuβΕ+«X\‚ξ†&³,‘+KŒ+«_WVu…xJ’Ι.Lώ2₯Ήγ Gž*ε²RY‡Z™[TηΑΙYΊ’Η+ _;a4'TAj‰@‹§ήΩ ½σΰΦ&ŠΌΫΕƒ <• OχΙρΜ€Ος>φΊώ2@ΉΎ{J½Γυ»βL _J°£Ω¨Γχ”IΟ'ΨϊϊiŸ.ΑϋΗΟoώτCŸύD ½-Ž)hΚΙυF‘½d₯)ε’Μώ΅€ ΰGσ‘½Cž:I―_fQlζ‘AύLN4RMF„…B nƒ€\ΉHœiK…ͺδ,hC­€Dk[KQX6.4¬Σ)HCaE±»Σwr½ώmNN&‰’Ά’ΨDδ<±w-‘ώb©Έ“)0‹c€± ˜‹Fdn DΖ03fΙ@‹DΖ ΞpͺQ kΒΦ­„`‘Α0˜˜@Βf”+€ Έ* ’%ΜOΐζ“H*s‰€VοjD,8In”‘μ]ͺF~ŒΞ”Ο"VσHβJΥέ ––%W8‡:©–ΝQΤ²H₯ Zφ¦(`Ξ%έB%MB₯8Μω$“v9J^ΥcD ²δ#Ρ€ΜmΆ›8’S-; ,Ρ!œΛΤa:Α©ΓŽπ{'θ¦Vd’Ι}l²JΡ<‹.E‰9Ϊθ±§,“,SηK*ρ‘*ωe5‹ƒKΪ‹ d₯DΕΙ+-½Σe[β'ώ·fF­₯αIjƒίΕ3ͺπ!˜ e°•t”€&eiIW#–χ‘‹6-ΥΦ>\ tΙδ€HiaΒR—ŽTdVιdfš ΨT”85*)&ΐSZ‘Θ”†F9©-: €>M LΫ$Jη΄t5ή‘ΊFw ­κΠ†€ kΏ΄eVςΑU­nm+/9 '…L”M™dV΅ΊΧ*u5!_ ©\ΊT“’K[EΥVPUj3™G”,ššΪ–“†4ͺεͺWcΩΟfV€œ}ά 3†– ŠSpνkyOMρ€ >α†l™°[οa”J2ζQTΛ„ΰZT5Ήmo[ŽΑφΒΈ}Ytώω[Lΐυ¬-0KχŒp]ς±@»QQ.sΏΫdt η₯±Ζ; Γ°–½J(/|­@ΙωbΒ½φƒ|σ+…ϊς7βύ/}+`x°ΐμ¨-‚©°ί/ΑΏΦF€#ό„SψΎ°π«α)XΈΓ=©Δ$FLβ›ΨΔ…8±ŠWΜbJ΄£Ε0ޱŒ—βΜ‘Ζ6Ζq,δ γαΖ>Vp·υή!Y4>r Š<_+ωΙ@2”«‹c)OωΚ6v2–™Ό+cωΛBπ²‘ΉΜ -ƒωΜ6³ΙŒ5£ωΝHs‡Ωά 9ΓωΞρ΅3‚ιμ 7γωΟPΠs~ω, AϊΠφs“ΗώkhD;ΊΏ>‘ΧιG[Ί •ŽΖ€΅‘θK{Ϊ ™.Ζ¦‡ΡιO›šΤ₯u›G}κVη9ΙΙ`5BνκZo8Υ¨΅‡qmλ^Σ‚Χ—Πu&€νλb³Φhvmμf›Ψ΄MmNΠ!Ψ”†u΅·½je‡ω ΜζΆΈSn—cΪγNwΡέ_ύj[έπ~GΉΜ…yΗϋή’fχ²g­o|ϋ»ž±ΐ―M{ϋΰ7σΐn„;όΒ ψ»NρˁΟΈΖ7ΞρŽ{όγ ΉΘGήοŠ›\ήqΉΚWΞς–³Όδ'y™SξςšΫόζ"‡ΉΜwΎjœϋόη8Χ9Ο‡ΎώnύθH'ωΔ‰Ξtr\<ιPzΖ…ήτͺšζRΟϊΡ©nυ[λ7€ υ€‹μ9_ΊΧ׎‹§@@Ω‘wΉ§έΫlΟ;}ΑήρΔ=cwω €( ο{Ÿ€άο<Ϊ=Ξu½[ώΦF9ΰη`±'㠈;Ζ @x΄o>d<ιΰχ8„>υ ύθπωŒ“>ρ§ƒγ)―φΛϋώλ™xδz€0>ςswΈ3@Ξ'ΐp|(€π ΎvOΟcœωr>T/όήώόΏ~Η½?~ώψ½γοxΏ/€όg€ΨcOώΏο^υϋ·{Π·Ψ‡qτΧ°μx‡Η{x‡~XnΧqp—}@xGxΖχybgw‘w΄Wθ~#H"h‚r@xrׁ Χ| X‚εχ€8ƒQΖwηΙWxί7v$zΩ· P}‡ƒw ΰwΘ‡ƒΚηx /ΈGΘr•GƒVΨΘqˆ‚hΧz¦GrGx)x}ΑΗ|d·…ή‚;8a˜yp7yW…W8‡qfƒNθqΠ€cz `w x pο‡|G† yω—q‚θ‡x~hwxψTh~tx‰˜f‡"w‚bg6Χ„"Χ‰>'‡˜XŠY‰¦~#§hˆ(hw+χz\¨ru7Š–hŠΆšψv…Χ€Θ‹*…Ηη‰"ηwΎXs€x‹Θψb¨8wΜΈrǘŒΠY،ΤrύΨXΉXά8u΅˜ΰΈΣ؍δh€ίŽθ¨Œcι؎?ΆŽ2ζŽς¨ πȎσxψ˜ϊΈό؏ώψ;python-graph-1.8.2/docs/class_hierarchy_for_grapherror.gif0000644000175000017500000001167012016145554023071 0ustar morphmorphGIF89a³=„ώΣΣΣ___???ίίߟŸŸΏΏΏΓΓΓ‹‹‹ΠΠώΏœœ_NNhhŸ‚‚ίΆΆ?44‹qquuwww§§§!ω,³=ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙl:ŸΠ¨tJ­Z―Ψ¬vΛνzΏΰ°xl˜Οθ΄zΝn»ίπΈ|N―Ϋο²~_ΜσM~€ƒ„4‚…ˆA‡‰Œ#‹Ž‘5’•|”–™+˜š]œž‘ ’₯S€¦–¨©¬K«­―°³C²E=i 9kDΈΊ:Ά΄Ζ»PΒΎ; k7ΠΌ?ΚΛΝ;ΕΗά8¨Ή0ΰβ)ΠΞγ α5Μια α *εΜ6ϋΤ™@7B;ξ u[Ψg…4Μ$8.ίA|"žω'"AΈ Ξ(x(@uυώr‰8°/ “.‘€ .–χ\j4σΟδ») °˜3#Δ€€d“hP>¦bΓ«/@1+p`λ:₯σνDˆ«Χ±ή…•G¦ΨlhίЍͺˆphΈ–¨`nΎ[»’E;σ+΅cg>›FνPfώ"|λ+ξ&¬˜‘₯X;jfΝ΄ΨψΥlϊΈsη|&}‘USDHՏΓR3€@ d5?»T0»ΆQ—dΥpόόŽ™θȜƒ@,M•­ΏΒ~λ2…ΥΜΨΛTM3μγo ά‘ύ Y[eΌΎ‚d+5z@θ|E˜όΗΜLΈΪxΝHSƒOε ο€Uw›MβΉ–Φ5η…ώ3‚z9UUvN’.z½τz=T^…ϊB`Ύ΄v_Y_ύ„…@υS‡+iHα[ ”’ tž P MEΈx" ―I¦γ"‚ζyφ`„LΒJ~'†D@j€Ρ]^=6φhNε(iτ¬7O…Νγ₯}’ιRzνΩs–g'%•c]yW–ωΔή–hΌ&GK6)θe>T‚ΡEVJ½d(’£RBΨ εKf`dZ‰Λ΄)…θέ )i½…€§γdy莸'ΩLŒ:CΣ£ϋI*£υεs)Tš:‡$‘ƒ{Βu2č±H+μBΚΒΐ̊Ζ<«D³ΛώC­ &Ω6KΆΣVλν(ߊqmΈ¬ŒKζž+JΊκ Αn»šΌ ―ςΞ+I½φ“/„ψξ{CΏώ‚ΗΐlπΑ'|Fΐ “pΓ‡ϋpΔ ;qΕ3yqΖgΆqΗ 3ςΘLςΙε’¬²½&―μr&-Ώ,³#1Οl³ΐ7ηάdΝ:χ<Ο>νΠBΡF'MJ7ύΣNGέ­ΤTΓ\υΥχb­5#Poνυ/_‡}‰Ψd\φΩ_tφΪ(¨Νφۏΐ΄ΒtΧmχέmΘ]‰Ϋ"λ ίέξ·63 >8Ψ2~ψΏ…/ΞuγŽ#’8-“G.ƒΪΧh£F0ώ!nω ώH+s£Τδ„θΩθϋ9θ,ƒλ(kP;ΠΖΰ@χhK‚μ#Dιε«³ΒX %QΉθtTGή…dΖH:ςyaGS­ΤR z‚7QEEόξΝ‹ΤεIHUlπ{huβ‘`ΕfϊbƒiΉVdn‘V™–~Ε·`5†q–ό…±ΜόΪ2ϋUι ΅ΣϊΖΆ™¬‘ir8“R遺ˆNΎ€ž\ψ<Λ#ΔQ“δΖ‚Νρ tJ³Aχ hX d`ΫΈσ¦•ζαM‰Pη ύ6l”ΰΣΉ(@$ΰdΖs σdΓ‡βžC³‘€BΆΙ«2ΤDIGH ΪώR>FΔ>qEF*"Αθ,€Ÿ7q‘?R6>tž"‡,Ώr«†'aiNp±Ι›ξ”%4ΌCOγλ˜$σ1Ή‰MqZΚ”RW§PΩGyβRτΞδ'F² r|l› T…(WΙδ/†’)k5©ŸδjW™Nat*„|Š,P’‘)«ΩrJiε-UL%/IJ CΩG# KΟl3›YiρΑšGε4“hnρΑ›Ωά&΄™2q rζδ9S±ΞmΆ³οdfΦ³χŒ!ήφΙΟ~,Λ'@C&Ёv¬ ΝBZ±…2΄d§C#Κ°‰RΤ_½hώΎ2ͺΡyq΄£νϊ(HΟ%‘JΜ€ ,)J«₯•ZΜ₯«k)L%Σ™jΜ¦‘«)N³£ΣzΜ§‡λ)P―"Τ‘φΝ¨p+*R­΅TΚωσ©PjݚΊL―)ΥfW₯'U"Ά¬&«[εfΨΌϊ2²Ζ+¬q+Z!C…Μι'‘’CŽΗCkΧxΘƒΟ@Π­2xΘ [Ί;Ή+―ίΘέλ»ΤΝξV4HMIΦc¬z₯‹²Η17‘˜υΐΐwΚά#UIρ½ pο"ΚΫRΒχΌDN•ώ«¦F08―~ν\J†w(%·Γ‹;z{»μ‘@Έ@ξ™09”ίΑp­κ3 ώΫχΓπ€4B"ύ ψϋ²/вΛWrΑ›ύ½/ΤRόΣ§τšŽ-ACΈΫœ3Ό«ΠŸ“]γH0&<Ν–T£Β ²°ΎΤιξΊŽθQ7α˜N€B"šΪBxŽ_’°£'!εƒΜqΙk@όIΔnGθ±α ωS :±‡ιŠΑδž6^12ΊSZfL)¨>1%£‡ž4™ΰF7‚bXΦhίΨ‹Ϋb–j$G駎!γt͈’44˜6|ρ"0层Ρ0}' œ4ΏG₯‰Ž–gBWΡ6Տ„€w35ΘKf1“U€S€θΘ2ι-Ρ`&ώψ§FxΡ~P²ŽCΤa(B‘“EΖ¬“―H«]Β*•Žϊe€„Y©S„W²Lf§D *ΈΚ%Ή"•˜}ζ$@Μ-Υ •$ܚUZγƒQLMη·Ρl˜YWv1lBτΨDη³ΡΊlUlΪͺΧήZ΅QΆν¬AΫίΦ6b₯Jξr›[y…gΊΑΊξ―u»έ±€7Έε΅wΣgχΎš½σ ˆ}σ[†všΏξ0‚Gmΰ§fΒ“†π…ŸΣαFk8Δ· ρ‰ΝβB«8Ζ­ ρ/Νγ=λ8Θ£ ς‘?Νδ7+9Κ™ ς•OΝεγ<·ΜgNnx· υ7ώ$§nύLφ\>7Jq4Z„!S†EUFX6FB6gΦeΩΥpW[>)KaFc&CAK†k8B]rφ€bTbΎ—PΒz†]vβgZ‚H‚'hΡCh:B&o‚)+©hž”==&x‘zX"=ͺei‚€iP~[E «δi°Υ(Ύ΄*£Y―TLΔΆ)΄„*Ο1΅Ε_(Z(dvUA†Ά'«Τg$lΌ–…zΔ„£uΙΖ2xΞVuu†‡)¨oy(pΨ4T·Q:7€BˆJ3ˆ,CsŒΨˆxs ‰ά&‰ΜF‰*£ˆ–H8™H2˜Έ‰ήΰ‰#Σ‰ (!£xP₯ώhЧ¨P©¨Š«ΨP­θŠ―8m±XQ³1’X‹pˆ‹$₯‹DΗ‹ε‹|Œ%ŒtHŒπr‹ωζˆηfŒŠ ŒζƌSηŒε?ppΨ˜ΪΈά؍ήψΰŽβΈ0ΤΈ f Žθ˜ŽκΈŽκHŽε¨9ΐŽς8τ8Ž<ψŽΔpŽυΈόHξˆLύ8Ž6`Ή ‰‰†  9‘ωy9 Ž 0υΫΈi‘ι$鍠 9  "™p’χ˜’3 ί“2YΠ’7I“Π‘ή2i#y1I’ώκ8)3™Ž(©“˜΅’άΨ‘U©L pi`Ψ–MιL‰H©”]‰_I•oIJ‰€––m©W‰•› •4ι‘έ¨–e)d™–g0“f0“_i—h0”j‰ΰ‘HΙ” )˜™“|uΙ’π’-iP“Hι@RΩ™ ™ ”‘I˜ΧΘ”u©$)š@›J9š-ٚw Ž{™™3΄™έȚ―y“/ι“)“"Y•-IΖyY›©Οι՝ΓYœ¨Ι›˜ι›Ÿδ—Ω(”HYšΡy›€©š°™›)`žΰšΥ™ζΉš»ι\i€9ώŸίΨ›ή Bΰψž)d‰"I–>ɘ‡iŸω”τ™$‰ ŠsIœjέٟΦžΩL)PšH ˜Γω‘€9’BY•"ڜ šˆ9”©ι’νiGy"ʝΘJ<Ή"ω’ιŠ‘Γ’‘ϋ“yΩ£λȟ@ _©”ui€σˆ€@š£N:₯θ₯*₯Tš₯ήh₯ύ‰₯Zϊ₯ΩΘ₯ήι₯` ¦bκ›8IΪ—iUkΚ¦mϊToͺ?:§¦°0i`§πτ‡€zz/(‰ ~ϊ§ S§iub7ŠqVj ƒJ¨tj¨½‡‘κ¨Ιr¦‡: “J©Υh©Uυ/œͺ©.Π¨ͺώcŽ™ ͺίYͺ;Y ’jͺp*Mθς©W «©κ «ϊ§²š$w«ΖX«/'Όz‘Ίͺ‰W¬₯ψ«'GqΔ*‰ΙZ1—¨‚Έ¬x%.КpΣZ —P­6‡­D°PΖͺ¨¨J§\£­>%IPRݚ­ίŠs0CΕNPTη:ξ ^―#•§žPmφšPϋJ3Σ―ό§[°s@°›°nΐyGEŠΕˆ«„©σ‰ ±Ϋ©LΕ8λ°Γ(±ά@-ΞͺWΫ±8±{± ±±ψΥ°)‹²³κ²—ϊ± ³1²œπ Ξ£;u&F€upͺ­ Λόχt*±tΡ‘ε …40cώ_Ζ?Μz²7V>‹=7D£1BbL«[{|ΐγ±Q[΅ϋc‚uWηuj $O;²(@wkη (Xγ…]χwΈβΕAΛ΅+«Ή C@‘ΆΕyhΧ=ΥΆlη U³3;vŽΫ–uLΡ‘;¦B#ν!f{‘Y³gΙuΉn»X搋Ɩ·ΕΘγ\P$nTvŒυΉ©k!«ΛΎ«ˆiƒΆ‘”iώH­„―°·ΰ›%‹η<Ξiζ=>ΝΚΌΰ>$Υ–αCn{½ Ά?ί΅‚ΊsΕω[’ύ;ΖφρDX"Ε?Qԍ$b­Υ‚ΔΥJ!ΥπA$!Φ9ν½jTD.bkΈw=ΨΞq…ΦKΕ†$Ή4ΕJ2lн)}ΝΓA:†τ†©€‘+ؐΧiqΌ?ΊV…”Bk+RΓγ₯ΑYiΈΘέΓ‚ΰΖ€)½φk³"j«ΆY–-Ω«ΩŸW‹­I‘f32ڞA+±«Σ”³Ή{0‡ΞwΜν$ΚR L}MaVj[ΈΣ\Φκr³Dέd°‡ΝΝ2ΦΠ ΅Η8έ­Pέλ­ή HΠ³ΰήρΝΆυάσ-ή»ίίΝήεdίύΝίϋ]²2+ΰδBίNΰ ΰξέ B «¦ α~W^αž¬Ίαήαn!;python-graph-1.8.2/docs/class_hierarchy_for_graph.gif0000644000175000017500000000551112016145554022014 0ustar morphmorphGIF89ak]„ώΣΣΣΠΠώ_NNhhΏœœίΆΆ?44Ÿ‚‚‹qqΏΏΏŸŸŸ___???ίίίΓΓΓ‹‹‹§§§!ω,k]ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙl:ŸΠ¨tJ­Z―Ψ¬vΛνzΏΰ°xL.›Οθ΄zΝn»g‚Έ|N―ΫοψΌ~Οοϋ€‚€8ƒ†‡ˆ‰Š‹‡7Œ‘’)o—N–Ž˜œ2š5Ÿ’‘%₯£¨=§ž©­&«0°j²²³·/Ά.ΊΈnΌ+Ώ½a΅ΒΕ±…Ζ£Α•Ι΄ΜΝΠ'ΛΟΡoΣΥfΔΩΩΧΨάmή¦ΰcΫδΝβγηΞ6ιλLζ4)συ3Wϊό(ώ°ά…¬Ζ={τήq'‚a€ƒ( ʐXb Šƒcdaa½4βΝ€ €B ’&ώgPα Ι–(VΒ΄ς2WA(O–T8đÜ(€ΚZB&‹œDc$at9DΘ°‚* T”π€žVΊJ° ΒΎΈzMaΦ$°~ε¨VΒάaιY5 ΧDZ±wM΄}ΛΒ!©d#φ ΠυΑLŒ8Άy²ŽΚ΅Γ‘ψDgfό]@`±TC‹ψ\‚/Ψ¬FΫ- »5겡Y“p]˜Ϊ ]!?‹•jΊj-."mΒ‡yg—ή•ίΌ9£/ŸσΟlœ•όδ>°@_μκ"°Ξ Lύμu9Ω§ηŽϋ;ρ¬γΛ“ώO½œΐ―ά€ΒpΒ‘ΗάqΙΑώΖ\lXα3v'D6›wrE ϋ‡a}υ ~EajˆG&žΕ!‰šη.\h Ζe•ΰvV9η „%`U~΄Χ}Μ-Θΰs‚Χ#οΕQσɍ΄YΨ Iͺˆ‚T&ψ'ΩΧ‰ži€Xβ%KAΦ£‹ΥρؚiΖFIL@§œu&hz%tfKq΄Dζjnξ—Πj&D§’ι“gW{ώΧ'>–)hm/Β¨‚—]U‡˜ϋωi₯ˆΚΙ&mr<ΰθv&q &ͺqtJβͺ΄΅JΗcœβΙ*¬_vθj…΄beλ™ΈΩ Ώ’ψicΦ6κ­qΒiΚ†ώ~δζ’wJ֐&::žΣV€Χ΅’1J­ΆeF)‡pε‚›ιΌ΄‹ ²Kh=ΗΡ&š“|F§Vf™dgdθ3'U’R«šΎ50€€¨Š[ΑΟΐΏ?ΑKΠο|_IΆ°\ ―Ά1Δ\’΄sl%yΞKγsοΑtPΎ$σλ―^Χ-Όž1ΫΈ¬ΌB[βσN8cJXa τ·274rŸ:]ζvͺJaS_QΝχ^Ν°Ξ&ΜcέΙ;apΒf·‰OŒŒi›<\’Ϊ%±νήsp˝5Όο*pBχuβΕ+«X\‚ξ†&³,‘+KŒ+«_WVu…xJ’Ι.Lώ2₯Ήγ Gž*ε²RY‡Z™[TηΑΙY:’Η+ _;a4'TAj‰@‹§ήΩ ½σΰΦ&ŠΌΫΕƒ <• OχΙρΜ€Ος>φΊώ2@ΉΎ{J½Γυ»βL _J°£Ω¨Γχ”IΟ'ΨϊϊiŸΑϋΗΟoώτCŸύD ½-Ž)hΚΙυF‘½d₯)ε’Μώ΅€ ΰGσ‘½Cž:I―_fQlζ‘AύLN4RMF„…B nƒ€\ΉHœiK…ͺδ,hC­€Dk[KQX6.4¬Σ)HCa±»Σwr½ώmNN&‰’Ά’ΨDδ<±w-‘ώb©Έ“)0‹c€± ˜‹FdnDΖ03fΉ@‹DΖ ΞpͺQ kΒΦ­„`‘Α0˜˜@Βf”+€ Έ* ’%ΜOΐζ“H*s‰€VοjD,8In”‘μ]ͺF~ŒΞ”Ο"VσHβJΥέ ––%W8‡:©–ΝQΤ²H₯ Zφ¦(`Ξ%έB%MB₯8Μω$“v9J^ΥcD ²δ#Ρ€ΜmΆ›8’S-; ,Ρ!œΛΤa:Α©ΓŽπ{'θ¦Vd’Ι}l²JΡ<‹.E‰9Ϊθ±§,“,SηK*ρ‘*ωe5‹ƒKΪ‹ d₯DΕΙ+-½Σe[β'ώ·fF­₯αIjƒίΕͺπ!˜ e°ς€•t”€&eiIW#–χ‘‹6-ΥΦ>\ tΙδ€HiaΒR—ŽTdVιδfš ΨT”85*)"ΐSZ‘Θ”†F9©-: €>M LΫ$Jη΄t5ή‘ΊFw ­κΠ†€ kΏ΄eVςΑU­nm+/9 '…L”M™dV΅ΊΧ*u5!_ ©\ΊT“’K[EΥVPUj3™G”,ššΪ–“†4ͺεͺWcΩΟfV€œ}ά 3†– ŠSpνkyOMρ€ >α†l™°[οa”J2ζQTΛ„ΰZT5Ήmo[ŽΑφΒΈ}Ytώω[Lΐυ¬-0KχŒp]ς±@»QQ.sΏΫdt η₯±Ζ; Γ°–½J(/|­@ΙωbΒ½φƒ|σ+…ϊς7βύ/}+`x°ΐμ¨-‚©°ί/ΑΏΦF€#ό„SψΎ°π«α)XΈΓ=©Δ$FLβ›ΨΔ…8±ŠWΜbJ΄£Ε0ޱŒ—b Μ‘Ζ>xooŒγ/D>&p:δ"ΗFnŽΩ δ$;ΩH~2{άd)[Κ4Άς’ΧQε+{Γ]6ς–Ήζ/› Qφρ˜ΡQζ3»9ΎiΦπšqA‡7ΫΉ uΎπœSη;ϋΟmΞοž9Ρη? …ο }ώ‘εC;šΌVȒӐθG[Ί •&39"}ιN£Ρ›F¦=MκOƒ:“ζBžKΝjFŸΊ©ΎΒ¨[MkJsΊ±ξο­kΝkWηZΦΚxu―‡μ]ψ³&Ά²E±κϋΊzΩΠ›kkaGϋΪΖHΆ~γicϋΫ°Ά6y7μmp›;Ϊ0¦Λ}ξv£šέPΰΆ'ΔνξzKήF4½νΝοΫ63φCŠεέο‚;CHπmπ†ϋ»ά x.ξπŠ3yΧr €Ζ7ΞρŽ{όγ ΉΘ €qŠ[όδφ-tΖGΞς–»ΌγN7Κgα(―όε8ΟΉΗ«όošϋάΙvΠΉΠ…^ώ‡ŸύΝ7ΊYnς£;]ΟqXΊΤGήτ§[ΑIŸΊΦ7^υ«{]ΠQί:Λ ΈΌλ_O»’Γ.v‘3@ 8ϋΎΥNwgύγ({Θ°€`yή°½‹νuO<8ξήρΌΗαz/<Π:,`γ“7|αηψ#^ρ ‡γ1/€(@~?ΙεΠyύς›—CάγwΙ~ξ‘Ού;F―ρΌw^ςd@ηΐ€€žδ |ήπz^·'Έξ§ΏήΐοΠΏΎπvΥs_~gΩγNΘ3 ϋχ;ΥqOύφ‹žνΏςžψž (}ΰŸyΠΥώΒ‡·~η~HnΫr±f§~7€o·} wΪ§qogvΡw€xΦ‡z7xΘ·q…—WeW‚δWzg~Έ.(m ΘrΟ7vΰ}Kχy/˜ƒΪyfw-χvδwƒμ§ƒFθj!€₯gƒ#—wΩG„x„RΨΦΧv:‡ƒS˜…YP…VˆsX¨…`Θ`<Ψ…Jχ…ax†6†dHtEˆ†nΈ…Ηo8‡;‡z@‡xˆ€vˆyΨ‡~ψ‡€ˆ‚8ˆ„Xˆξ;python-graph-1.8.2/docs/class_hierarchy_for_find.gif0000644000175000017500000000054412016145554021634 0ustar morphmorphGIF89a8%γώΣΣΣΠΠώΏœœίΆΆ?44_NNhhŸ‚‚ΓŸŸ!ω,8%ώ0ΘI«½8λΝ»`(Bižhͺ¬y΅p,»Φlίη[|οΐ 0H«˜†Θ€’P€—ΠhsςŒZ‘SIυΚύeI»ΈχݎΉε0p4 ¨B`¦Κv‚!X@xv%:C <RCwH & €‹<€q |‰‚„I”L€' ¨&ͺ‘£Hšp<%u€‘ m•Dƒ5jA΄|~‡ ”₯mXΑFΓ@Ηsu‘ΆΊΟ’Β…AΨ«‹₯Ιε%m~ŽΠN?₯Ϊ΅έͺ½ˆΉΏΐΰΡβΞ\y$° Α‚ίQ‰‡PΙΑ†PBt¨P Γ‰―ΒαΨƒǏ*<‚Yq„Ι“(Sͺ\Ι²ε‡;python-graph-1.8.2/docs/class_hierarchy_for_euclidean.gif0000644000175000017500000000077012016145554022646 0ustar morphmorphGIF89a]%γώΣΣΣΠΠώ_NN?44ίΆΆŸ‚‚Ώœœhh§ˆˆ!ω,]%ώ0ΘI«½8λΝ»`(Ždiž— lλΎp,Οτ›ΦxοςΝΐ ΛG(Θ€rΙl:ŸΕJ­Z―G©e…νzΏQΥL.3΅yΝ& )κΆόϋžΔηxk]rŸ'H s{}r  ސHxŠŒJ€ V†ˆ‚JE› œ‘U˜*O•+•ž ΅ ¬ˆ·Άž ›Ž΅³*,„Eͺ€gb[±MŽ Χn₯Ό Α+₯€aEΙ* ΧΩγFΉ„ζήK°–M•‘€Ή»·Ž Μ΅ƒΊρKΐ)A½(₯²υzζΧ‘xΣT“ΦŒΌ?₯‘‰!0¦œά΄@ΰH§oψΚ ƒ(`ŒŒžŒR@LΘC½"°S"‹όHΕt/˜'‹ίΆQt©„SΈœ,Ύ™ ¬j8†NM6ˆVR%.›,™&Ιy`Y*N»žU:0iέ:‚Ί0ΆΦμZ‹άΦ!]Jm^žΏPδμD0αΓI #^,²e_ƌC&,y2`yB2kΖαc³ηΟ-:ƒ½…ιΣ¨S«^ΝΊ΅λΧ°MD;python-graph-1.8.2/docs/class_hierarchy_for_digraph.gif0000644000175000017500000000562512016145554022337 0ustar morphmorphGIF89ak]„ώΣΣΣΠΠώ_NNΏœœ?44ίΆΆŸ‚‚hh‹qqΏΏΏŸŸŸ___???ίίίΓΓΓ‹‹‹§§§!ω,k]ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙl:ŸΠ¨tJ­Z―Ψ¬vΛνzΏΰ°xL.›Οθ΄zΝn»g‚Έ|N―ΫοψΌ~Οοϋ€‚€8ƒ†‡ˆ‰Š‹‡7Œ‘’)o—N–Ž˜œ2š5Ÿ’‘%₯£¨=§ž©­&«0°j²²³·/Ά.ΊΈnΌ+Ώ½a΅ΒΕ±…Ζ£Α•Ι΄ΜΝΠ'ΛΟΡoΣΥfΔΩΩΧΨάmή¦ΰcΫδΝβγηΞ6ιλLζ4)συ3Wϊό(ώ°ά…¬Ζ={τήq'‚a€ƒ( ʐXb Šƒcdaa½4βΝ€ €B ’&ώgPα Ι–(VΒ΄ς2WA(O–T8đÜ(€ΚZB&‹œDc$at9DΘ°‚* T”π€žVΊJ° ΒΎΈzMaΦ$°~ε¨VΒάaιY5 ΧDZ±wM΄}ΛΒ!©d#φ ΠυΑLŒ8Άy²ŽΚ΅Γ‘ψDgfό]@`±TC‹ψ\‚/Ψ¬FΫ- »5겡Y“p]˜Ϊ ]!?‹•jΊj-."mΒ‡yg—ή•ίΌ9£/ŸσΟlœ•όδ>°@_μκ"°Ξ Lύμu9Ω§ηŽϋ;ρ¬γΛ“ώO½œΐ―ά€ΒpΒ‘ΗάqΙΑώΖ\lXα3v'D6›wrE ϋ‡a}υ ~EajˆG&žΕ!‰šη.\h Ζe•ΰvV9η „%`U~΄Χ}Μ-Θΰs‚Χ#οΕQσɍ΄YΨ Iͺˆ‚T&ψ'ΩΧ‰ži€Xβ%KAΦ£‹ΥρؚiΖFIL@§œu&hz%tfKq΄Dζjnξ—Πj&D§’ι“gW{ώΧ'>–)hm/Β¨‚—]U‡˜ϋωi₯ˆΚΙ&mr<ΰθv&q &ͺqtJβͺ΄΅JΗcœβΙ*¬_vθj…΄beλ™ΈΩ Ώ’ψicΦ6κ­qΒiΚ†ώ~δζ’wJ֐&::žΣV€Χ΅’1J­ΆeF)‡pε‚›ιΌ΄‹ ²Kh=ΗΡ&š“|F§Vf™dgdθ3'U’R«šΎ50€€¨Š[ΑΟΐΏ?ΑKΠο|_IΆ°\ ―Ά1Δ\’΄sl%yΞKγsοΑtPΎ$σλ―^Χ-Όž1ΫΈ¬ΌB[βσN8cJXa τ·274rŸ:]ζvͺJaS_QΝχ^Ν°Ξ&ΜcέΙ;apΒf·‰OŒŒi›<\’Ϊ%±νήsp˝5Όο*pBχuβΕ+«X\‚ξ†&³,‘+KŒ+«_WVu…xJ’Ι.Lώ2₯Ήγ Gž*ε²RY‡Z™[TηΑΙY:’Η+ _;a4'TAj‰@‹§ήΩ ½σΰΦ&ŠΌΫΕƒ <• OχΙρΜ€Ος>φΊώ2@ΉΎ{J½Γυ»βL _J°£Ω¨Γχ”IΟ'ΨϊϊiŸΑϋΗΟoώτCŸύD ½-Ž)hΚΙυF‘½d₯)ε’Μώ΅€ ΰGσ‘½Cž:I―_fQlζ‘AύLN4RMF„…B nƒ€\ΉHœiK…ͺδ,hC­€Dk[KQX6.4¬Σ)HCa±»Σwr½ώmNN&‰’Ά’ΨDδ<±w-‘ώb©Έ“)0‹c€± ˜‹FdnDΖ03fΉ@‹DΖ ΞpͺQ kΒΦ­„`‘Α0˜˜@Βf”+€ Έ* ’%ΜOΐζ“H*s‰€VοjD,8In”‘μ]ͺF~ŒΞ”Ο"VσHβJΥέ ––%W8‡:©–ΝQΤ²H₯ Zφ¦(`Ξ%έB%MB₯8Μω$“v9J^ΥcD ²δ#Ρ€ΜmΆ›8’S-; ,Ρ!œΛΤa:Α©ΓŽπ{'θ¦Vd’Ι}l²JΡ<‹.E‰9Ϊθ±§,“,SηK*ρ‘*ωe5‹ƒKΪ‹ d₯DΕΙ+-½Σe[β'ώ·fF­₯αIjƒίΕͺπ!˜ e°ς€•t”€&eiIW#–χ‘‹6-ΥΦ>\ tΙδ€HiaΒR—ŽTdVιδfš ΨT”85*)"ΐSZ‘Θ”†F9©-: €>M LΫ$Jη΄t5ή‘ΊFw ­κΠ†€ kΏ΄eVςΑU­nm+/9 '…L”M™dV΅ΊΧ*u5!_ ©\ΊT“’K[EΥVPUj3™G”,ššΪ–“†4ͺεͺWcΩΟfV€œ}ά 3†– ŠSpνkyOMρ€ >α†l™°[οa”J2ζQTΛ„ΰZT5Ήmo[ŽΑφΒΈ}Ytώω[Lΐυ¬-0KχŒp]ς±@»QQ.sΏΫdt η₯±Ζ; Γ°–½J(/|­@ΙωbΒ½φƒ|σ+…ϊς7βύ/}+`x°ΐμ¨-‚©°ί/ΑΏΦF€#ό„SψΎ°π«α)XΈΓ=©Δ$FLβ›ΨΔ…8±ŠWΜbJ΄£Ε0ޱŒ—βΜ‘Ζ6Ζq,δ γαΖ>Vp:δ"ΘFVo‘œδ&™ΖN&Α{oΛδ([Yt°ς”ΟQε+{Ω]ξρ–»ε/›ωΑ<φρ˜ΡQζ3»Ή iρš…η7Ϋ9 aFπœΫΫζ;ϋΟu.πž•θ?Ί yfο /ώ‘θC;э^Η’ΧιG[ •Ζ€q›ιK{Z .Ζ¦υ[θO›Z}†Ζ¨·κS»šΤ©¦3.ZύκZ—£Τ·X΅‡cmλ^ϋ‚ΦlΠu&pνλbw"Λ©v|ymμf£Ψώ5³MνV Κ~rΆ«Νm.@Τ¨žv·ΗMgqwaێΈ6ΉΧ­ju³Ϊ ίf·Ό{o8ƒΪέσΞ79ύnϊš[ίGΌg̈;ΰηI« ^p`ΰ;αŸo₯Ύ£;βwEžε@€Ž{όγ ΉΘGNς’›œwΖWθ:sόδ0ΉΜOΞc•³όζφ΅ΓΜwΞσ™Ϋη@οΛ{Nώτ’ƒόαAO:…‡nτ¦χιJΊ γΰτͺσκRΟzΞ©nυΓλZ;s™~rΰ ΌN€ΐ_?ΈΨη²› ΐΐΆο}qΏ8έlΗ\ θΈ:nvΈόH€ΪPr³/οŽ9Ψ Οωvη½δ 0@°wΈγ=τr`ΐΫ €χ$ tX»Η]ΏzΦӁςš—{ηwo »ƒοs|ܞ(@ς}ŸξΫφŽ_Βΰ[OςΝσώϊ|ώόΘUγKήψj7;ξ[οφ³+~ @~ΗOy³3ΐν²?}υuύϊ'Ϋπ"—?$―wώΎΏγό·w}Χq y€ηv€Gͺ·€Ϊ'rΦgx_ψrΓ§€Ν'~ˆz‰'~v @yς§z}W~¨Gyi'{Ή'xΨ‚»φ€!χ|κwzΟpΗΜ·v{χy5(}ϋχy₯Wrθ‚DˆmrΗχvΐ‹‡x(y`y(—xΞ‡xͺG…ow… θ„˜€+X„`¨qGΨsϊgrn7€E7„aΈ†δ5†0§zp„0χwM§†lx‡χƒ2‡zV(sf·xFg‡x8ˆ¦‡lwˆλG„ΈˆώfˆˆΘv‚Θˆ’nψˆ]‰“˜‰V‰–Xu˜¨‰ ˆe—‘XŠY0Š€hŠͺΘ`¨Ψ«ψа‹²8‹΄X‹Άx‹R;python-graph-1.8.2/docs/class_hierarchy_for_common.gif0000644000175000017500000000551012016145554022202 0ustar morphmorphGIF89a]]„ώΣΣΣ???ΏΏΏŸŸŸίίί___ΓΓΓ‹‹‹ΠΠώhh?44ΏœœŸ‚‚ίΆΆ_NN!ω,]]ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙl:ŸΠ¨tJ­Z―Ψ¬vΛνzΏFxL.›Οθ΄zΝ€ίπΈ|NΗΆοψΌΎ\οϋ€‚'{…†‡bƒŠ‹ŒŽJc’“”•–—˜™š›˜cŸ ‘’£&‘œ§¨©ͺ“ž€―°±`¦«΅Ά΅­²Ί»Ό½ab·ΑΒ›ΉΎΖΗΘΙ,΄ΓΝΝΕΚΡΣ²ΜΞΧΆΠΤΫάέƒΦΨα¨Ϊήεζη]ΰβλ™δθοπρLκμυ”ξςωϊϋ;τœD €  @‚ͺπρ[Θ°‘ ” J˜ΰΐB™ “&€ Q€J9όXρbF ώ$΄Kδ°₯Λ—" JB9&QBp@SLΐ1{ $Sα¦Mžv €Π’B˜P£z“I!e… b,Rt!©WΕLΐ*@X²ci•Τu§X€[²”J·n7™(γ:8)ο͝XUvπΧΑΰΑ|g ˜p“$JŒ—žΪL9–Μ€cQRΨθ jL;{-ά•`՝…9{PΰJ7•cΛL“P•Ιδ€qmi€½³.©8a―g+_Jζ”vΞ=Ρμη½e»Ζcκ[·ξ4—Ήωσ€dΪ['½ϋχYΤ―ΧΎύϋOδΟΏVΏEθ·ί3εhΰΏdώ7ΰ|ύ!θΰƒ2Έ`0 Bhα…(H8a6bθα‡!"βˆj€hβ‰₯¨βа‘θ"ˆ,Ζ(β‹4ΦψC‡6ζ¨c|˜±γ@ΑG -Ζ4dH&ω+IΘ‘JF $”MΖ@₯”XzΘδ NZYa–`*·₯ ]pe˜hΚ6feβpfšp:τ¦›BηοΜΙC›AψˆηŸΡθ Ÿ β葟ψΩ‘Šθ£p8š£ωI ι₯<ΪY₯T(Šι§‹~Ή(–‚jͺ™š¦“^ͺ§Άκ«³,Rͺ«—ΞΚ§}ΨJ+š°ζJŠ»N)j€΄ ¬‰½*‚+(ΐ‹`³~,ϋk²ΞώH-³Ϋ@[νdΪΚjN·Ϋ6t­eρ€ξ9ζb»§ηκΓ.7~›n»’Ό‹.]φΪ(γΎόφλ/nώ+πΐ›BΑ'¬πΒ{Œ,ΜΕ[J΅|JlŸΕDš‡ρίYρΓ7t̐Θ"Γω1Œ/G2Ε£²Ζ/;{ς‡%—ΜΟΚ2·LsΚbΖ|μΜ/$ €N( ΐBέΓ(ΰ‚ΡH½tΣKςμBt0ν4ZWMζ X#ΡucŸPΆg?€σ @€ΈΡφΫ=΄€ q0wέάύͺΥ-μ=‡έEώχΧ2~„α\0n‚γY@ΎvΖ1@ΐ0τ•kn@ώV θ"½΅Ω™o‚ΡΔ}z†’@Ίι)`ξ9η)°ξϊ2€³`ΉνͺΓ €η€―@; ΐ€; ΊSmΒρ¨ίž{ί»W‰xεG_žΊς]ότ­;ίύη'@oBςΛ—O½ψ#4ϊΣΔ«> θ―Ύώό”Βǝ€Πd Z†§ΊJ/qƒΣ Ό°msš`41€jq;@P₯‰@ƒΞKΰ'»αAƒΰ.(Α£m°ƒτΣάΦD(NΜg)ΰŸκόΐ1€άc χH†‘„t 5ΘΑΖ0„e@β —ψB'~P†" aφΤv=θ{<„ώ‘97Ζ,±„ΐ4₯]Πo—Γ"HD " ‰,¬c}ψΔF±kl£ήxE(1ƒΔ#›ΘǀЏd°! €vŠN±s€Τ @4ArςrRk[ Κ|R$ΠβέΑ΄Q&@so‹€&•¦ΚˆαndVy4Lώ–Άα,ΝH^βr‹“γ ,iΛL~p“„&(‰&JRb”Ρτ (] LY>“–» ζ1ΣΧΚ_Ί-˜5f-oYGλΥ€RΜΌ&ύ€ιΙlκΝ—₯<₯Τ&Ω·: Mt$ζPΝR’‘Ύ|ε9½9M²“Ήδη8PUτšMhώ7…ωM‡φ’ΘΤ_†TΠΆΟPh[#₯ ΐ΄‘!t-5ΐK͈;LΖt¦$Έ I5χ?©YŽ-ŝJΩL΍₯ϋœΰtjΞΰ§ κθ°˜ΐ¨nC₯R“!’zο€ΞjVΕ S˜’§΅ιYΏGΑ-F5²£*QmΪV€‚σ{P=šTγZUΊU«)t§™VPž¦0¬r«KΝΊXšZυ¦l,θyΑš^΅i½j:σΚFΈŠ•n~λ]η9ZΚf/΄Θ¬T9»ΧΟ>Ά’ε’HQQμ­mbΠάK57sφ>TθoΥXSΚνœ<ζξI7άb²ŸLσΫώ·άTwΉsKq™kΫ1θ”νu)U3Τ–»ΞΥ­pΕΰ[φ—¬λ-r―{άζzΊύ ΐtΟΉ]h»όMoί’;Hρς·Ί²¬yCzΫϋξ– ν ¬>Η[χŽ`Όσ υΫ· —tΆonρ^‚ΨI6.Φ6όFŸΔυνξˆοΖbΣ Α#Ν1 4‡΄Έέρhδ\ά€Ι €ƒ‰Όε?‹χO#Γ1˜œΣi[9§^£‰ΞrA&"θ.ψΆ–ͺŒϋδXφ€ ΅*_Λt —A™B4kSΗοTΰc¨eyΘE ’Όd晝#0σ•³wηΐΩΛn. §ώ,»4§πΠμM΄`•)g ΧȎ&r’όηΎυyt~²€]W\H @Σxέβ’Ρ|Y5ŸΡ„sιb N£mωΥb@5 ~ΊκX·ΪΠΈn3­'=ΙσΡ‚Δ­Šι,:ž2{ΎήUθ2—as‚ZtZu“Ν’ZV7‚*žγsίζΏlχ—Ϋ°ρ6lΐM즀†DCv(αljΧ;vφ彫]mΓέ½Ϋ·©–\so{ήnPwwρ—?ΏΫ‰ς¦&½Sψμ}7Ϊηιΐ·VΑΣ©γ-2ψΏπώ‚;ΉŸ΅!zρά*”Έg<ΈΔΣΞ”'Έαη‹[@;_PtΠ\ώΊ c’θ£Σ9>tΠQT† ΐdc§Π§~4“>—gΣ~ξ7yΎ1 ²ƒΊΤ›φ‘±ŽμfάΉΦΐu«ψΙpv8κ0Ισ΄\oB_zήIGη£}ηΞ.O"ͺ=v[/²Ϋ9όRyVπX§;FΩx΄²έ0`ζθΎψ¬πLGΊμ”ώwΏήςω½ |Α€›ΎπΏ:qΚ·υG|μ.―z±ήo}o:ΪΛnυUFžφΆ΄}ΧwŸ_ΖD[UΣθφƒθ׎Ώ8”{¬<μΟ€ϋησ~œ»ΕMίΰ?υq ΈσΧ ύ%p?ω‹]‡<²›’³ύΩηUΟΈkŸZ° χ8Νη88~  ΐ?Ξ”^D5χGX H X™9$ό—θ5³5*ΔyO#_90‚;χΆΖ&½S(Έ~Ζc‚-π‚%ΘVg%ƒγ=»&ƒ,@ƒ5˜…Υ><Έ>Ψ+˜}τ·3H8σ3Ξχ ε1KΨ*”t!Q¨2Sx*Uh!WΨ3ση*[!]8M,a…-HeΈ+Γ0nψ†0p8‡tΨ-ux‡x˜‡z@/|Ψ‡~ψ‡€ˆ‚8ˆ„!;python-graph-1.8.2/docs/class_hierarchy_for_chow.gif0000644000175000017500000000061012016145554021646 0ustar morphmorphGIF89aC%γώΣΣΣΠΠώhh?44ΏœœŸ‚‚ίΆΆ_NN!ω,C%ώ0ΘI«½8λΝ»`(ŽŸ`žhͺlλžΨ+ΟtΧxξήαΐ pH,a—“qΙl‘₯sJ}šxΥlZ‘jΏL.Ε .[X³:(ž§ c-lKήN…@Ag_“&Z {r?|ZvxCˆ …(•ƒ( ƒ|… ŠEސA—&&ž q•…{‘=΄ŒgiEz Άq>…œ­>΄³{ Ÿ©£QF…•?z>‰ΪΓ­zzqίF€E‰ … ƒ•‘Β‰|z©½©“ΞΟh€=Σ(οϋzs4¨g*ƒγ u)G$A‘ΨT9ΓJ%}L £p Γ>6eΘνiF$I5&O†μθζ£Κ*)_6byΗ₯L'"uθΤΙc§Ο= έA’¨Ρ£H“*]Κ΄ι;python-graph-1.8.2/docs/class_hierarchy_for_basegraph.gif0000644000175000017500000000571612016145554022656 0ustar morphmorphGIF89a]]„ώΣΣΣ???ΏΏΏŸŸŸίίί___ΓΓΓ‹‹‹ΠΠώΏœœ_NNhhŸ‚‚?44ίΆΆΓŸŸ‹qq!ω,]]ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙl:ŸΠ¨tJ­Z―Ψ¬vΛνzΏ@xL.›Οθ΄zΝnƒίπΈ|NgΆοψΌ^_οϋ€}{„…†w‚‰Š‹ŒDc‘’“”•–—˜™š›—cŽŸ ‘’£œ¦§¨©™ž£­―°^₯ͺ΄΅Ά•¬±Ί»Ό½b·ΑΒ©ΉΎΖΗΘΙ*³ΓΝΞ”ΕΚΣΤ―ΜΟΨΓΡΥάέήΧΩβ΅ΫίζηθYα•γΑνο›ειφχψHλ”π·&ψγT/ŸΑƒoμ›DAJ(T@αα₯)XΑ¦ˆ-Zκ8‘αΌNbώͺ\ΙςΕBI'L|g‘ 0R|ΨpΜΌŽbϊ½k‘›’ŠztΠsŒH\)[J*υ%N3’RtPαf; +X렝X %8 #ς+Σ2Δό#Š© Υ»xΏY ϋ°£Ϊ±Ά£8a#έ΅t΄Ht°Eΐiχ Ανۍ(δέΜY/°L$#υ› PLL΄dj"ˆy’j_‰Ω.λhΨ‘\׍ڹ·οcVͺ|A@žŠW˜τ¨XJ§;&^|υψε~ΓΕδtxυζnΝΏΓ‹‡e«Ϋ\X° 1ύlΓeήι>¬©άτ‘ž΄dwΌΰ|v‰0g\V UώΠOb2ΑFμ9ˆj„fœ$ .ΈV fu‘£­Β€$–8ˆ€]f™΄›-ύ™(γŒWX…P²ν‡‰@YΑ8"@Y…Οlgά‹štΔ"9? ιδ“K™β”‘Δε•Xξ %•)Z™ε—`Ζ°%—πxζ™hž0&™β˜™ζ›h"ηœrΒiη&Щ瞈ΰ駝|*hjhMͺθ’]j£F ‘%€7Β£’fͺ)d¬`) ˜n*κ¨jvκΒ§-PJκͺŒš*ͺbΊΙκ¬AΊZ¬4¨Jλ΅ΚκιΊς*¬oΑjω‹―Γ&λM±ΐ&ͺ²Π.k«Έώκ3m΄ΨΖςl”Tl›ν·‰0λD΅Rx ξΉ²\Ϋ-ζ’λξκbAn£ρΎkoυj1οβήλο ωΚ²HΏLΑpμ ²0 ‡ϋpΓ»N<Θ.S¬©Ε€D,JΖϋ ςΐӌr–;β1/&ŸlbΛ‘¬ \Κ.χF³+2KsΝ+ν¬mΟ>σ,νΝΎδŒN»Bsƒτ9F糴’ƒF-υΤT«CΥXg­uΣoνυΧ`‡ΝF \Χz΅Œe‹6΄δ=£Ϋnχ¬PΝm 7Ϊs»\·ΘgΏœχΙ{γy·ί6Δν0Ωvχ]βΪ† ψƒ/ώwȏ»€8‘€\žyώ € ›wŽ9θ’»€ψ žΣϊθDΌzα3΄Ž„μ]ΰ~‚ξZπΎ β1 N ™πΔχ <.ςΚ ΐό©«»ύΛ‘=υ΄ΛpύΫsΎ γgQ>πjΚPzPζΔ ΐϋ$ f"Ψ/Βζ°οξ>ό*ΨŒΧ?Pα/ϊγ_ ΪGΏψ₯@€dAδ^°>σÜώV @XΠDSg‚ϊ―”^Υ=ωqŽ}‘όθ·Α„3Τΰ Lh‚†p‡*ΔαFX@ΡˆE$Δ$V }) —€Λ‘!s Θ  ³ˆΒo £γώβGΐΕotT ΐζΔ@€Το`@>'8’π‹cψ!ηgF7 ‹ch#9Η9*ρ}°Γ£τ˜§κ@Š€’Η€E-ΖOŒ2τ"ΒhΙ¬qx~„£―xΘ;–AŸ€&EiΘ:"RŠ|αοZ¨HΚP’†Δδ%;©I0#ˆεBχΉ6N}―μ₯ G€2”…$εμ˜ΘS–@˜Δ1]iJ_ΎΡŒΟdf4)YΚj’‘ƒβ ‰?pš§+@ζ²)OφNxH>PΟl’ –ΜKIθς™€χοœπό@ ζ½ρše(ηάYEƒ24 …eώD/κPYͺ`+`'CίYΗxΞΣ€φΜ>υιN~ž”Žφ$¨EZR…n΄‘«T"E :Ό‹.2£ ΕιCgy+ˆ΄₯:Ν\?QšΝ•ξs©0εθ*/‡?ͺj” pjKΙΠ€Ξ£5½κ$ΪQ= •sV΅*@΅ΪΞ1tU¦=₯iJŊӳ’σR%πκgΕΛΑNŸ$@θ0‡ϋ Φ…Υ¨έyΨΔ’ |}_O·ΎUց€΅θHγ·9ΑžN“5„lEθΉΚΎρ²ωC@`ΥVΞϟi$jQS°ΧΙώ‘„™}­kΨέ:v¨Œυm Υ(ΛΣώͺΥ,c‰λY›ΦΠ΄œC-rώW»άΞΒφ,œ-m5ΨWά&W·„νmxΛΪΖχΊφkiΫZζ·΅?…ξ0›ΫδUW·ΞMͺFΣ‹ΏυnΦ½² ξ ε+έϊ–—Ήθ•νS0T@Oxbx_aί7†ΡVΨ§”δι…ƒ‰]~―§’ΑϋžΧSGXzφœž1―7βvxΔΘ ±‡Iœ<»Ε‘S±τX¬° š Α46ρ'L ‹!½sΤπ‘I c—ΨΖN±6w\⏠Ιρ$œγ)g΅Κ=žά:=d(KOΙ€₯π’ΝP?5wΨΑ`ρm?Χε“Ν<֟“΅|bζΥyΕqΦk %{Ί?KΟ`Φs–αώάg)Ϋ™ΚΙ³2¨ςze΄Ο™h]ρΰNL @Žΰl(U7HUOσ’ρƒ,qγ'a@βo}T_ΫHΌΑς’Ÿ½Τ U]ΊVoξΥ/Œ5h]λ#Γ:Χ”†ΑΌήΧΉK—NΨ›ξτAmκQ“QΪ8­ta½jj»΄ΆηU_·τΨν₯bΈmMn ŠΩΜN€³3np:ԟΖφ™)zm|ŸΊέšάœώΦ-†{?W–ζ6λm?‚;ΨΘξΆνξžΦΰ$¨lΒ%ών†[ά؏j#'Ν`RR±©)‘¬Όρ§rχΙyΛ<­’Λ=,ο-χ4±]‹Qž…ΆψŒ4W¦E©˜ώσΟΒtEρΟ…HrZώΨδδ9ΝW>υ™»9Ÿ-? d‹Ύσ{FΕηΰzˆΉ©ƒΞN\°vQ Θ̝άλšΙzΥ΅N¬“Φκ\:μΦΨ?°ΓάΚd+•‰S½έπΔνζX=όwKώθ_ί(β“=―φΉΣΎ4^ڈ?Ό― °ŸηέϊόiΎτ£½ύŠΘ€Ώω£ŸGΚαΝ#UtœŸRiUΆώυ΄η©fTMΪώ€Έο4k½μξw+Qσ˜ΧθρŸχyΤW_5W=υIΏϊ– Ÿψο„ώνϋε?Ί°Hύ>Š‹/ώv’_ω΄?σΧξΏΛ›ΏύΫΧ~κKΐώΣ‹ώϊήΦN΄MφfΙgF¦Η}ρη{˜~΅Ηyjσ~Όw{ˆb¨?8=ΩWzΕ§~~—7~εGHy‚[+:Ισ*¨,˜>Ζ/Έ@%F5Έ;7θt―Rίƒ5ƒ:Ψ‚8p=@ˆƒoƒ;˜+Ιφͺt-p>6π„L·]§F ΅T˜vδs‚.°…Qθ…X(&sRDRRXK©…,†1`†πNnˆ`†W˜…ιS€d€“„8°‡›GA~Θ„ΞW€H„4ˆ+pˆ}8\„8†^P[§ˆ*ΐˆ˜’Έ?”˜–ΨηHxΕ7…(ŒC7MV&3θ₯¨7§&©8«8­ψ%―HŠ£ψ/•'΅±H9³ˆ2 ‹·θ/m#6ΖxŒUs5ΘΈŒΜΘ0ΊΦŒΠΈISΦxΨ˜ΪΈά؍Ώ;python-graph-1.8.2/docs/class_hierarchy_for_algorithme.gif0000644000175000017500000001011712016145554023044 0ustar morphmorphGIF89aΘ=„ώΣΣΣ___???ίίߟŸŸΏΏΏΓΓΓ‹‹‹ΠΠώhhίΆΆΏœœ_NN?44Ÿ‚‚uu§§§!ω,Θ=ώ` ŽdižhͺlλΎp,Οtmίxο|οΐ pH,Θ€rΙ| žΠ¨tJ­Z―Ψ¬vΛνzΏ`AJά,›Ο"ςIn»‰μRόM―ηζ#Ό}Οwι}‚ƒyc„‡ˆ…(‰mŒI=R wSD“•:g™; T7¨—?’£₯; +”ͺ0΅·)¨¦Έ Ά5€ΎΆͺ Ά *Ίͺ€6ΠΏ&½#ΏΑΓ4³)QΤO ΆΞάΝ"βPΤ" ΆΤ P βͺRΏΚ”"ΠΞHδ ˆͺ@€IQ*ύc°έjωˆΙ`0†μƍˆ'`^½χδ‹²Oœ'ΰώN*p`%°Žβœ9μ‹₯Λ™ˆΕ$¦ ΜX8‰¨„κ€[QX–(`h¦+[Δiπ%3 F½)E'Ε4=»ύΜtEJ;D˜V4„ ΏͺUλ,_&š’Š wχkLV\ΫΥn ΐζ”wl‰‘zϋ$ncƒbEΖ’y°Ÿή—}4΄₯OςOLˆJ"=ΑύŒ5Uσ·cΖηH’`*"5ROl FϊDΥ”fύN€ΆΌ rΧ9_ΙΆ5’φ»(IŸ˜€T Uθˆƒέ}o,VR3ι^σ₯ΔnάŒ”hήΧxξ?t“„ό5Ω&Œ$x‰|$πώυTqΧ–K―₯QUv₯₯@|τ`W\Ξ•”QQ\ψHρS2Ά!#^UΘ…APU¦β2ΎψΟcVm8j–5"‰šEqβ‚οPΈ† @€TDΡΔ&ڈ£€qΠγ ,qv#%—™'™0KvfΠ…Sf„ M€‰K’a^Ψίd Β(₯)IfGVJœ3ZŽ΄Ξ\ξ±pVΩ8BD‘H )τ£J(ϊC>ƒ9κ₯‘jgι¦fHΚι§Fx κ¨AˆJκ©<˜Šκͺ7¨Κκ«2@Ζ¬΄Φjλ­ΈζZ¬6DΒλ―½+¬Ύkl Ε«l…Λ6 C²Ξ: m΄ΛώNKν±Φ^;lΆΪΛm·Ό~ ξ«βŽ»jΉζžŠnΊ£Λξ§ξΎ»iΌς:Jo½Žά‹o"ϊξ{HΏώpΐ} Lπ\GΒ ΏΑpÏ@l‚WlρΕV$ρ°ΔrhΜ±Η‰~ςΘ"±±"%ΓrΚCœœΛ*“ŒΖ+²l2Ν8Έ H(±ΕrΚφ €w¬œ‚51 B‘ΫΣh ΣTΓL₯»ωάτ~ί}ΒLδh‘: iOjτGLƒ―΄§> QB^Tΰ€€(KuQy£{ώT[8©0ΆΜ˜βTΫ·E˜₯ͺnό㘳91XfΌcσ¨G<Άc€ € Ð2υ‘X‡œW"-eΘEΚΡ‘ω‚d$%Ι/JV’Βd&5)0Nv“e(E‰0R–” Ce*Uι0VΆ•ƒ%)Λ‰Υς ΄Ό%ΚtΉ„\ς—„€0‡IL‹9—–8&2e‘ΜeΝΞ|$²’ωΜiR³UΝΌfΦ ιœε`!OάΑgrΑ9›!YΐμŒω|¦ΆœN6Η δΙŠΓ•*›(PΪ τ‰ «ΩΟi5°K‰¨Q(e`Yr:(J΄"ΓpγJψ”ΰΦ4"·―”kΙ›ώΩ<¨Ώ%œ2JPΆRΈ39NτΔB†Ρ‘“z"&ΓXiΤΰFΉx ¦όΡ N%ΚΣΒB09ή‹Η•Π1.,­{œέt'9”š‡‰©ιRϊ±ΉΠm$9BͺκPyRŽ(4ΐs›ΒhŽΔMό.wJ]eΞΌΧΑ³xaνΆ“ΣwD°%ˆα‰hθρ–‘βΥ™`E:R7R vA_kbh7ΓΖ6ΗwΝSMάN#=χP/Φ« ο‘΅‘.yQNΤG"μP8έH«)L£μΞgΚlL˜Όžϊ#½Q[xθWΠ 6=šq{€ϊ–μ€"m‹Ρ ό‚˜ω _ώλΑΖH·gtΑg>3\šŒΣΆdEAO:Θ*‘%-ί†Β­ΘC ‚αˆb$†¨Ο!€₯―‡(œβ(³™]οlΚͺΕΪι†A|lˆ)κ©«Uٟ8!#–)‰ΰTR@φ—3a¦*Κ  >‘3w•‰ T˜ήΥOD,°5ΕNN’Σeτ䍋°FGT›Οϊ1 μΨ!ΌFFrΗ’ƒ3YΘk(¦”§Lε-μ+΅Δ²,΅ K.»Λ¬³*ŌJ2›Μ€D³(Υ J6λψΙη„σάμc9'ΣΞoΔ33υ,M>cΣΟ{΄½MBΪΠ±Bτ‘ώ esUωѐžς θ,²lQϊc–Ft¦ ½iBwZПt¨yζڜ%%»3πζ³Μ‰ΘD“¨^ΖΪ‚ΠΖΪυάκœ'έ~φzjΌπη^Jƒ¨eδi,@ΥN 4c;”ΨGžq8(κ5ι^TlOΡh)8κΩ”ΆM‘Ή HnLŒ’"ρ£%….8‚Ž8ΟΉE6NqΚ7Ϋ΄ΆVΙO ԟ 5sKν`9γ4–€ ₯IuSR‘ΝYw©Ϋxΐ'V―‚΅/Œ oUpΦΘΈ₯wυ-έ‡]wΨOvqΥ,%σXΐ6$΄c\„ϋ„˜c­"‡ήέ{XΕVΙΜZ„ψfγώ8…X˜…KX…κr…Zψ…`˜ƒ\H*H†fx†18†νβ…7O-@I(‡tψ‚ „Tπ…j*exƒrψΠ‚ „‡˜ˆvθ‡X@˜‡R`~h„]Θ‚88s(θšXˆž¨‡0 ώΠ‰1‡‡‰¨‰@’ˆƒ‡Έ‡?HЦˆŠ8ψ‡πΒ†4h‡‹Ψ‚°‡šψnΈ‡Γp‹pŠΑθ†Δ‹QŠ«XаŒ±θŠ1¨ŒΜ(ΛXΗψ† ΈƒΊΘ)XƒŸ8‹-hŠ«hŠ₯yh…‹‰W¨Œπ¨Πψ₯ˆŒα8‰λ’ψ`ŠυˆˆϋhTh‰dΘ‹2˜‡{˜‡t(‡ΖȍΐȍŸΨ‚n(„荸”h‘ ‡ξ8ˆ0ˆ’’Xˆι“6XŽσ"‘Ω8ŽΘ₯¨Š₯θAΉ‘π‹=Ɉsx”-”¬(’Iوώ& ƒFi”C9Eɐ7 ‘kˆ‰4xQI`ɎΤΨ“”8“ω‹وn‰ΏΨ”Fω‚h©‘BΙ‰fŠψΈ<6XŠθ—Α8.ŠΡX—.˜Ψ8”κˆ˜Ω–„9˜UY•ί¨‘UY„{9:邇x‡yˆ”(’₯HΨ8–sŠμΈŽŸyˆάxšŽyšC˜xš$ι‚€I¦ω™Yy™BΗ•L˜hœi¨•€˜™:XŒ=I‹ΒΉœ-ΩƒΎ)„€i‰ΘœΤ‰“ŒdœΤ™Bhφ‚ΪωbHœ»ψœΰYž:ȝ†rŽζΉž7ˆžω’‚π)ΞŸρ9Ÿτ™‚o¦ώΌ©GϋyGύIGGκF 3Κ2ZHΈ˜ %γ •Ά ŠiZ‘ϊi‘ˆ‘ ͺ‘8‘γ‘’#’±rŸ&z’Q€Œζ* ¦’ŠΖ’’撚&£œF£žF£6w[₯Vͺφ (΄+IΤzN5UE²4ν 0Π£α#Ÿχ€x'ΐ ο0v1 tΥ\NHSvWc‚3Fڐ%΅B/ ₯π4B *%n"lšQ€Ε%cκ ΄l ’ bDϊτ Ύα7%CΩĐΧ—OrΡl ε¨* β0"‘§’!.υ5 Ό‘ %₯P―QκUΆ$Vώ±;Πn^ΪuœŠ₯–1 τ¦­Š¨ ϊ€Κ1 Ά±ϋΦ:5XP§•aΜeΜUͺΆ*ΐRΒJqq’=aεrA$¬Šs8Αš8aOBbqIυ9\υ<ψ­ΫAUYr"χ;ρW>3ΠΎ#\w>ΈpZ>C’!vg¦€ β:V˜*>έσZ¦v5%¦΄Ί° 2uO€Έ%7b\ۊ6ω3¨6f­ΑAΧ[Α5‚‘ۈχJg%ΞΈ°¨h³[91C›₯±Ά]rwI+cΰJ:S[‘'#Φ3dΐ¨}S6tBzƒ9κ₯‘jgι¦fHΚι§Fx κ¨AˆJκ©<˜Šκͺ7¨Κκ«2@Ζ¬΄Φjλ­ΈζZ¬6DΒλ―½+¬Ύkl Ε«l…Λ6 C²Ξ: m΄ΛώNKν±Φ^;lΆΪΛm·Ό~ ξ«βŽ»jΉζžŠnΊ£Λξ§ξΎ»iΌς:Jo½Žά‹o"ϊξ{HΏώpΐ} Lπ\GΒ ΏΑpÏ@l‚WlρΕV$ρ°ΔrhΜ±Η‰~ςΘ"±±"%ΓrΚCœœΛ*“ŒΖ+²l2Ν8Έ H(±ΕrΚφ €w¬œ‚51 B‘ΫΣh ΣTΓL₯»ωάτ~ί}ΒLδh‘: iOjτGLƒ―΄§> QB^Tΰ€€(KuQy£{ώT[8©0ΆΜ˜βTΫ·E˜₯ͺnό㘳91XfΌcσ¨G<Άc€ € Ð2υ‘X‡œW"-eΘEΚΡ‘ω‚d$%Ι/JV’Βd&5)0Nv“e(E‰0R–” Ce*Uι0VΆ•ƒ%)Λ‰Υς ΄Ό%ΚtΉ„\ς—„€0‡IL‹9—–8&2e‘ΜeΝΞ|$²’ωΜiR³UΝΌfΦ ιœε`!OάΑgrΑ9›!YΐμŒω|¦ΆœN6Η δΙŠΓ•*›(PΪ τ‰ «ΩΟi5°K‰¨Q(e`Yr:(J΄"ΓpγJψ”ΰΦ4"·―”kΙ›ώΩ<¨Ώ%œ2JPΆRΈ39NτΔB†Ρ‘“z"&ΓXiΤΰFΉx ¦όΡ N%ΚΣΒB09ή‹Η•Π1.,­{œέt'9”š‡‰©ιRϊ±ΉΠm$9BͺκPyRŽ(4ΐs›ΒhŽΔMό.wJ]eΞΌΧΑ³xaνΆ“ΣwD°%ˆα‰hθρ–‘βΥ™`E:R7R vA_kbh7ΓΖ6ΗwΝSMάN#=χP/Φ« ο‘΅‘.yQNΤG"μP8έH«)L£μΞgΚlL˜Όžϊ#½Q[xθWΠ 6=šq{€ϊ–μ€"m‹Ρ ό‚˜ω _ώλΑΖH·gtΑg>3\šŒΣΆdEAO:Θ*‘%-ί†Β­ΘC ‚αˆb$†¨Ο!€₯―‡(œβ(³™]οlΚͺΕΪι†A|lˆ)κ©«Uٟ8!#–)‰ΰTR@φ—3a¦*Κ  >‘3w•‰ T˜ήΥOD,°5ΕNN’Σeτ䍋°FGT›Οϊ1 μΨ!ΌFFrΗ’ƒ3YΘk(¦”§Lε-μ+΅Δ²,΅ K.»Λ¬³*ŌJ2›Μ€D³(Υ J6λψΙη„σάμc9'ΣΞoΔ33υ,M>cΣΟ{΄½MBΪΠ±Bτ‘ώ esUωѐžς θ,²lQϊc–Ft¦ ½iBwZПt¨yζڜ%%»3πζ³Μ‰ΘD“¨^ΖΪ‚ΠΖΪυάκœ'έ~φzjΌπη^Jƒ¨eδi,@ΥN 4c;”ΨGžq8(κ5ι^TlOΡh)8κΩ”ΆM‘Ή HnLŒ’"ρ£%….8‚Ž8ΟΉE6NqΚ7Ϋ΄ΆVΙO ԟ 5sKν`9γ4–€ ₯IuSR‘ΝYw©Ϋxΐ'V―‚΅/Œ oUpΦΘΈ₯wυ-έ‡]wΨOvqΥ,%σXΐ6$΄c\„ϋ„˜c­"‡ήέ{XΕVΙΜZ„ψfγώω“@ω’9‰-*”Fy”Hω“C9’E™”Nω”ώPιKΉ-M•Vy•<9•ΒXΩ•^)“Zι-Uω•dΩ•a9‚c9“π“ ΰ’o) ΰ’uy—>If)’TΉ“6Y—O—/I€Ω’†ι ΰy©˜Œι“0Π—Ι•6ω–†Y0)•ι’žΉ’mι“Ω˜ŽΙ’`žΙ™2Ή˜ΰ“©ΉšYι—[™–0™—‹iš0`阼ι›πš†kωPœπ–Q0š€i˜zω–¬‰˜p集)ΎΙœPΠ–Χι›1y–αb›/9—Ώι†œyžPΐ™EyRΉ““iqi˜©žOžRπώ™Q0™Ppž9Ÿ‘ΉŸίI›by˜29™―9™wΉ– šΖi— ‘)••ω˜sΉ’k٘ƒižpωžQ ʟq™‘°‘$:“ΰ +˜9“φ©’Κιͺι‘£9£Ήι˜v ™9£+yΪ£ ϊ’7ͺ£+Ι£*E –Š– “ό)‚— ϊžTš£z£ͺšœΉ˜•Ή–¬šKΚ’&j’\ ™•i’Lz™βΙ’ͺI˜2 —κ©šυ tJ£Λ)ψΩ–ΪΩ‘Κω£}ϊ―‰€H¨q‰€kͺ“3Ή˜z €π Γ)Π–:’Ϊ–‘ ™p™©»ω@˜™ ¦qb*μω™Κ’j— jͺ‰J”OZ–° •+J.m«Ά ”³Κ*-z«Όj”Ήz.΅Ϊ«Βͺ’Mž―:¬ΘJ¬lz¬ΙΪ¬ Y¬,¬Ξš¬ΏŠ*' ’:y­λ—­Ϊiψ­ΰK;python-graph-1.8.2/docs/class-tree.html0000644000175000017500000002362512016145552017067 0ustar morphmorph Class Hierarchy
 
[ Module Hierarchy | Class Hierarchy ]

Class Hierarchy

python-graph-1.8.2/docs/api-objects.txt0000644000175000017500000007167112016145554017106 0ustar morphmorphpygraph pygraph-module.html pygraph.__package__ pygraph-module.html#__package__ pygraph.algorithms pygraph.algorithms-module.html pygraph.algorithms.__package__ pygraph.algorithms-module.html#__package__ pygraph.algorithms.accessibility pygraph.algorithms.accessibility-module.html pygraph.algorithms.accessibility.connected_components pygraph.algorithms.accessibility-module.html#connected_components pygraph.algorithms.accessibility.mutual_accessibility pygraph.algorithms.accessibility-module.html#mutual_accessibility pygraph.algorithms.accessibility._cut_hypernodes pygraph.algorithms.accessibility-module.html#_cut_hypernodes pygraph.algorithms.accessibility._cut_hyperedges pygraph.algorithms.accessibility-module.html#_cut_hyperedges pygraph.algorithms.accessibility.accessibility pygraph.algorithms.accessibility-module.html#accessibility pygraph.algorithms.accessibility.__package__ pygraph.algorithms.accessibility-module.html#__package__ pygraph.algorithms.accessibility._dfs pygraph.algorithms.accessibility-module.html#_dfs pygraph.algorithms.accessibility._cut_dfs pygraph.algorithms.accessibility-module.html#_cut_dfs pygraph.algorithms.accessibility.cut_edges pygraph.algorithms.accessibility-module.html#cut_edges pygraph.algorithms.accessibility.cut_nodes pygraph.algorithms.accessibility-module.html#cut_nodes pygraph.algorithms.critical pygraph.algorithms.critical-module.html pygraph.algorithms.critical.critical_path pygraph.algorithms.critical-module.html#critical_path pygraph.algorithms.critical.__package__ pygraph.algorithms.critical-module.html#__package__ pygraph.algorithms.critical.transitive_edges pygraph.algorithms.critical-module.html#transitive_edges pygraph.algorithms.critical._intersection pygraph.algorithms.critical-module.html#_intersection pygraph.algorithms.cycles pygraph.algorithms.cycles-module.html pygraph.algorithms.cycles.find_cycle pygraph.algorithms.cycles-module.html#find_cycle pygraph.algorithms.cycles.__package__ pygraph.algorithms.cycles-module.html#__package__ pygraph.algorithms.filters pygraph.algorithms.filters-module.html pygraph.algorithms.filters.__package__ pygraph.algorithms.filters-module.html#__package__ pygraph.algorithms.filters.find pygraph.algorithms.filters.find-module.html pygraph.algorithms.filters.find.__package__ pygraph.algorithms.filters.find-module.html#__package__ pygraph.algorithms.filters.null pygraph.algorithms.filters.null-module.html pygraph.algorithms.filters.null.__package__ pygraph.algorithms.filters.null-module.html#__package__ pygraph.algorithms.filters.radius pygraph.algorithms.filters.radius-module.html pygraph.algorithms.filters.radius.__package__ pygraph.algorithms.filters.radius-module.html#__package__ pygraph.algorithms.generators pygraph.algorithms.generators-module.html pygraph.algorithms.generators.generate pygraph.algorithms.generators-module.html#generate pygraph.algorithms.generators.__package__ pygraph.algorithms.generators-module.html#__package__ pygraph.algorithms.generators.generate_hypergraph pygraph.algorithms.generators-module.html#generate_hypergraph pygraph.algorithms.heuristics pygraph.algorithms.heuristics-module.html pygraph.algorithms.heuristics.__package__ pygraph.algorithms.heuristics-module.html#__package__ pygraph.algorithms.heuristics.chow pygraph.algorithms.heuristics.chow-module.html pygraph.algorithms.heuristics.chow.__package__ pygraph.algorithms.heuristics.chow-module.html#__package__ pygraph.algorithms.heuristics.euclidean pygraph.algorithms.heuristics.euclidean-module.html pygraph.algorithms.heuristics.euclidean.__package__ pygraph.algorithms.heuristics.euclidean-module.html#__package__ pygraph.algorithms.minmax pygraph.algorithms.minmax-module.html pygraph.algorithms.minmax.maximum_flow pygraph.algorithms.minmax-module.html#maximum_flow pygraph.algorithms.minmax._first_unvisited pygraph.algorithms.minmax-module.html#_first_unvisited pygraph.algorithms.minmax._reconstruct_path pygraph.algorithms.minmax-module.html#_reconstruct_path pygraph.algorithms.minmax.__package__ pygraph.algorithms.minmax-module.html#__package__ pygraph.algorithms.minmax.heuristic_search pygraph.algorithms.minmax-module.html#heuristic_search pygraph.algorithms.minmax.cut_tree pygraph.algorithms.minmax-module.html#cut_tree pygraph.algorithms.minmax.shortest_path_bellman_ford pygraph.algorithms.minmax-module.html#shortest_path_bellman_ford pygraph.algorithms.minmax._lightest_edge pygraph.algorithms.minmax-module.html#_lightest_edge pygraph.algorithms.minmax.minimal_spanning_tree pygraph.algorithms.minmax-module.html#minimal_spanning_tree pygraph.algorithms.minmax.shortest_path pygraph.algorithms.minmax-module.html#shortest_path pygraph.algorithms.minmax.cut_value pygraph.algorithms.minmax-module.html#cut_value pygraph.algorithms.pagerank pygraph.algorithms.pagerank-module.html pygraph.algorithms.pagerank.pagerank pygraph.algorithms.pagerank-module.html#pagerank pygraph.algorithms.pagerank.__package__ pygraph.algorithms.pagerank-module.html#__package__ pygraph.algorithms.searching pygraph.algorithms.searching-module.html pygraph.algorithms.searching.breadth_first_search pygraph.algorithms.searching-module.html#breadth_first_search pygraph.algorithms.searching.__package__ pygraph.algorithms.searching-module.html#__package__ pygraph.algorithms.searching.depth_first_search pygraph.algorithms.searching-module.html#depth_first_search pygraph.algorithms.sorting pygraph.algorithms.sorting-module.html pygraph.algorithms.sorting.topological_sorting pygraph.algorithms.sorting-module.html#topological_sorting pygraph.algorithms.sorting.__package__ pygraph.algorithms.sorting-module.html#__package__ pygraph.algorithms.traversal pygraph.algorithms.traversal-module.html pygraph.algorithms.traversal._dfs pygraph.algorithms.traversal-module.html#_dfs pygraph.algorithms.traversal.traversal pygraph.algorithms.traversal-module.html#traversal pygraph.algorithms.traversal.__package__ pygraph.algorithms.traversal-module.html#__package__ pygraph.algorithms.utils pygraph.algorithms.utils-module.html pygraph.algorithms.utils.__package__ pygraph.algorithms.utils-module.html#__package__ pygraph.classes pygraph.classes-module.html pygraph.classes.__package__ pygraph.classes-module.html#__package__ pygraph.classes.digraph pygraph.classes.digraph-module.html pygraph.classes.digraph.__package__ pygraph.classes.digraph-module.html#__package__ pygraph.classes.exceptions pygraph.classes.exceptions-module.html pygraph.classes.exceptions.__package__ pygraph.classes.exceptions-module.html#__package__ pygraph.classes.graph pygraph.classes.graph-module.html pygraph.classes.graph.__package__ pygraph.classes.graph-module.html#__package__ pygraph.classes.hypergraph pygraph.classes.hypergraph-module.html pygraph.classes.hypergraph.__package__ pygraph.classes.hypergraph-module.html#__package__ pygraph.mixins pygraph.mixins-module.html pygraph.mixins.__package__ pygraph.mixins-module.html#__package__ pygraph.mixins.basegraph pygraph.mixins.basegraph-module.html pygraph.mixins.basegraph.__package__ pygraph.mixins.basegraph-module.html#__package__ pygraph.mixins.common pygraph.mixins.common-module.html pygraph.mixins.common.__package__ pygraph.mixins.common-module.html#__package__ pygraph.mixins.labeling pygraph.mixins.labeling-module.html pygraph.mixins.labeling.__package__ pygraph.mixins.labeling-module.html#__package__ pygraph.readwrite pygraph.readwrite-module.html pygraph.readwrite.__package__ pygraph.readwrite-module.html#__package__ pygraph.readwrite.markup pygraph.readwrite.markup-module.html pygraph.readwrite.markup.__package__ pygraph.readwrite.markup-module.html#__package__ pygraph.readwrite.markup.write pygraph.readwrite.markup-module.html#write pygraph.readwrite.markup.read pygraph.readwrite.markup-module.html#read pygraph.readwrite.markup.read_hypergraph pygraph.readwrite.markup-module.html#read_hypergraph pygraph.readwrite.markup.write_hypergraph pygraph.readwrite.markup-module.html#write_hypergraph pygraph.algorithms.filters.find.find pygraph.algorithms.filters.find.find-class.html pygraph.algorithms.filters.find.find.configure pygraph.algorithms.filters.find.find-class.html#configure pygraph.algorithms.filters.find.find.__call__ pygraph.algorithms.filters.find.find-class.html#__call__ pygraph.algorithms.filters.find.find.__init__ pygraph.algorithms.filters.find.find-class.html#__init__ pygraph.algorithms.filters.null.null pygraph.algorithms.filters.null.null-class.html pygraph.algorithms.filters.null.null.configure pygraph.algorithms.filters.null.null-class.html#configure pygraph.algorithms.filters.null.null.__call__ pygraph.algorithms.filters.null.null-class.html#__call__ pygraph.algorithms.filters.null.null.__init__ pygraph.algorithms.filters.null.null-class.html#__init__ pygraph.algorithms.filters.radius.radius pygraph.algorithms.filters.radius.radius-class.html pygraph.algorithms.filters.radius.radius.configure pygraph.algorithms.filters.radius.radius-class.html#configure pygraph.algorithms.filters.radius.radius.__call__ pygraph.algorithms.filters.radius.radius-class.html#__call__ pygraph.algorithms.filters.radius.radius.__init__ pygraph.algorithms.filters.radius.radius-class.html#__init__ pygraph.algorithms.heuristics.chow.chow pygraph.algorithms.heuristics.chow.chow-class.html pygraph.algorithms.heuristics.chow.chow.__call__ pygraph.algorithms.heuristics.chow.chow-class.html#__call__ pygraph.algorithms.heuristics.chow.chow.optimize pygraph.algorithms.heuristics.chow.chow-class.html#optimize pygraph.algorithms.heuristics.chow.chow.__init__ pygraph.algorithms.heuristics.chow.chow-class.html#__init__ pygraph.algorithms.heuristics.euclidean.euclidean pygraph.algorithms.heuristics.euclidean.euclidean-class.html pygraph.algorithms.heuristics.euclidean.euclidean.__call__ pygraph.algorithms.heuristics.euclidean.euclidean-class.html#__call__ pygraph.algorithms.heuristics.euclidean.euclidean.optimize pygraph.algorithms.heuristics.euclidean.euclidean-class.html#optimize pygraph.algorithms.heuristics.euclidean.euclidean.__init__ pygraph.algorithms.heuristics.euclidean.euclidean-class.html#__init__ pygraph.algorithms.utils.HeapItem pygraph.algorithms.utils.HeapItem-class.html pygraph.algorithms.utils.HeapItem.__init__ pygraph.algorithms.utils.HeapItem-class.html#__init__ pygraph.algorithms.utils.HeapItem.__cmp__ pygraph.algorithms.utils.HeapItem-class.html#__cmp__ pygraph.algorithms.utils.priority_queue pygraph.algorithms.utils.priority_queue-class.html pygraph.algorithms.utils.priority_queue.insert pygraph.algorithms.utils.priority_queue-class.html#insert pygraph.algorithms.utils.priority_queue.__contains__ pygraph.algorithms.utils.priority_queue-class.html#__contains__ pygraph.algorithms.utils.priority_queue.pop pygraph.algorithms.utils.priority_queue-class.html#pop pygraph.algorithms.utils.priority_queue.empty pygraph.algorithms.utils.priority_queue-class.html#empty pygraph.algorithms.utils.priority_queue.__len__ pygraph.algorithms.utils.priority_queue-class.html#__len__ pygraph.algorithms.utils.priority_queue.discard pygraph.algorithms.utils.priority_queue-class.html#discard pygraph.algorithms.utils.priority_queue.peek pygraph.algorithms.utils.priority_queue-class.html#peek pygraph.algorithms.utils.priority_queue.__init__ pygraph.algorithms.utils.priority_queue-class.html#__init__ pygraph.classes.digraph.digraph pygraph.classes.digraph.digraph-class.html pygraph.classes.digraph.digraph.neighbors pygraph.classes.digraph.digraph-class.html#neighbors pygraph.mixins.labeling.labeling.DEFAULT_WEIGHT pygraph.mixins.labeling.labeling-class.html#DEFAULT_WEIGHT pygraph.mixins.labeling.labeling.edge_attributes pygraph.mixins.labeling.labeling-class.html#edge_attributes pygraph.classes.digraph.digraph.add_node pygraph.classes.digraph.digraph-class.html#add_node pygraph.mixins.common.common.__str__ pygraph.mixins.common.common-class.html#__str__ pygraph.classes.digraph.digraph.has_edge pygraph.classes.digraph.digraph-class.html#has_edge pygraph.classes.digraph.digraph.node_order pygraph.classes.digraph.digraph-class.html#node_order pygraph.classes.digraph.digraph.del_edge pygraph.classes.digraph.digraph-class.html#del_edge pygraph.classes.digraph.digraph.del_node pygraph.classes.digraph.digraph-class.html#del_node pygraph.mixins.labeling.labeling.DEFAULT_LABEL pygraph.mixins.labeling.labeling-class.html#DEFAULT_LABEL pygraph.mixins.labeling.labeling.set_edge_properties pygraph.mixins.labeling.labeling-class.html#set_edge_properties pygraph.classes.digraph.digraph.__init__ pygraph.classes.digraph.digraph-class.html#__init__ pygraph.mixins.labeling.labeling.add_edge_attributes pygraph.mixins.labeling.labeling-class.html#add_edge_attributes pygraph.classes.digraph.digraph.DIRECTED pygraph.classes.digraph.digraph-class.html#DIRECTED pygraph.mixins.common.common.inverse pygraph.mixins.common.common-class.html#inverse pygraph.mixins.labeling.labeling.edge_label pygraph.mixins.labeling.labeling-class.html#edge_label pygraph.mixins.labeling.labeling.WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling.set_edge_label pygraph.mixins.labeling.labeling-class.html#set_edge_label pygraph.mixins.labeling.labeling.get_edge_properties pygraph.mixins.labeling.labeling-class.html#get_edge_properties pygraph.classes.digraph.digraph.nodes pygraph.classes.digraph.digraph-class.html#nodes pygraph.mixins.common.common.__len__ pygraph.mixins.common.common-class.html#__len__ pygraph.classes.digraph.digraph.__ne__ pygraph.classes.digraph.digraph-class.html#__ne__ pygraph.mixins.common.common.complete pygraph.mixins.common.common-class.html#complete pygraph.mixins.common.common.__getitem__ pygraph.mixins.common.common-class.html#__getitem__ pygraph.classes.digraph.digraph.has_node pygraph.classes.digraph.digraph-class.html#has_node pygraph.mixins.common.common.add_spanning_tree pygraph.mixins.common.common-class.html#add_spanning_tree pygraph.mixins.common.common.__iter__ pygraph.mixins.common.common-class.html#__iter__ pygraph.classes.digraph.digraph.edges pygraph.classes.digraph.digraph-class.html#edges pygraph.mixins.labeling.labeling.add_edge_attribute pygraph.mixins.labeling.labeling-class.html#add_edge_attribute pygraph.classes.digraph.digraph.add_edge pygraph.classes.digraph.digraph-class.html#add_edge pygraph.classes.digraph.digraph.__eq__ pygraph.classes.digraph.digraph-class.html#__eq__ pygraph.mixins.labeling.labeling.del_node_labeling pygraph.mixins.labeling.labeling-class.html#del_node_labeling pygraph.mixins.common.common.add_graph pygraph.mixins.common.common-class.html#add_graph pygraph.mixins.common.common.reverse pygraph.mixins.common.common-class.html#reverse pygraph.mixins.labeling.labeling.LABEL_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#LABEL_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling.add_node_attribute pygraph.mixins.labeling.labeling-class.html#add_node_attribute pygraph.classes.digraph.digraph._edges pygraph.classes.digraph.digraph-class.html#_edges pygraph.classes.digraph.digraph.incidents pygraph.classes.digraph.digraph-class.html#incidents pygraph.mixins.common.common.__repr__ pygraph.mixins.common.common-class.html#__repr__ pygraph.mixins.labeling.labeling.set_edge_weight pygraph.mixins.labeling.labeling-class.html#set_edge_weight pygraph.mixins.labeling.labeling.edge_weight pygraph.mixins.labeling.labeling-class.html#edge_weight pygraph.mixins.common.common.add_nodes pygraph.mixins.common.common-class.html#add_nodes pygraph.mixins.labeling.labeling.del_edge_labeling pygraph.mixins.labeling.labeling-class.html#del_edge_labeling pygraph.mixins.common.common.order pygraph.mixins.common.common-class.html#order pygraph.mixins.labeling.labeling.node_attributes pygraph.mixins.labeling.labeling-class.html#node_attributes pygraph.classes.exceptions.AdditionError pygraph.classes.exceptions.AdditionError-class.html pygraph.classes.exceptions.AlgorithmError pygraph.classes.exceptions.AlgorithmError-class.html pygraph.classes.exceptions.GraphError pygraph.classes.exceptions.GraphError-class.html pygraph.classes.exceptions.InvalidGraphType pygraph.classes.exceptions.InvalidGraphType-class.html pygraph.classes.exceptions.NegativeWeightCycleError pygraph.classes.exceptions.NegativeWeightCycleError-class.html pygraph.classes.exceptions.NodeUnreachable pygraph.classes.exceptions.NodeUnreachable-class.html pygraph.classes.exceptions.NodeUnreachable.__init__ pygraph.classes.exceptions.NodeUnreachable-class.html#__init__ pygraph.classes.graph.graph pygraph.classes.graph.graph-class.html pygraph.classes.graph.graph.neighbors pygraph.classes.graph.graph-class.html#neighbors pygraph.mixins.labeling.labeling.DEFAULT_WEIGHT pygraph.mixins.labeling.labeling-class.html#DEFAULT_WEIGHT pygraph.mixins.labeling.labeling.edge_attributes pygraph.mixins.labeling.labeling-class.html#edge_attributes pygraph.classes.graph.graph.add_node pygraph.classes.graph.graph-class.html#add_node pygraph.mixins.common.common.__str__ pygraph.mixins.common.common-class.html#__str__ pygraph.classes.graph.graph.has_edge pygraph.classes.graph.graph-class.html#has_edge pygraph.classes.graph.graph.node_order pygraph.classes.graph.graph-class.html#node_order pygraph.classes.graph.graph.del_edge pygraph.classes.graph.graph-class.html#del_edge pygraph.classes.graph.graph.del_node pygraph.classes.graph.graph-class.html#del_node pygraph.mixins.labeling.labeling.DEFAULT_LABEL pygraph.mixins.labeling.labeling-class.html#DEFAULT_LABEL pygraph.mixins.labeling.labeling.set_edge_properties pygraph.mixins.labeling.labeling-class.html#set_edge_properties pygraph.classes.graph.graph.__init__ pygraph.classes.graph.graph-class.html#__init__ pygraph.mixins.labeling.labeling.add_edge_attributes pygraph.mixins.labeling.labeling-class.html#add_edge_attributes pygraph.classes.graph.graph.DIRECTED pygraph.classes.graph.graph-class.html#DIRECTED pygraph.mixins.common.common.inverse pygraph.mixins.common.common-class.html#inverse pygraph.mixins.labeling.labeling.edge_label pygraph.mixins.labeling.labeling-class.html#edge_label pygraph.mixins.labeling.labeling.WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling.set_edge_label pygraph.mixins.labeling.labeling-class.html#set_edge_label pygraph.mixins.labeling.labeling.get_edge_properties pygraph.mixins.labeling.labeling-class.html#get_edge_properties pygraph.classes.graph.graph.nodes pygraph.classes.graph.graph-class.html#nodes pygraph.mixins.common.common.__len__ pygraph.mixins.common.common-class.html#__len__ pygraph.classes.graph.graph.__ne__ pygraph.classes.graph.graph-class.html#__ne__ pygraph.mixins.common.common.complete pygraph.mixins.common.common-class.html#complete pygraph.mixins.common.common.__getitem__ pygraph.mixins.common.common-class.html#__getitem__ pygraph.classes.graph.graph.has_node pygraph.classes.graph.graph-class.html#has_node pygraph.mixins.common.common.add_spanning_tree pygraph.mixins.common.common-class.html#add_spanning_tree pygraph.mixins.common.common.__iter__ pygraph.mixins.common.common-class.html#__iter__ pygraph.classes.graph.graph.edges pygraph.classes.graph.graph-class.html#edges pygraph.mixins.labeling.labeling.add_edge_attribute pygraph.mixins.labeling.labeling-class.html#add_edge_attribute pygraph.classes.graph.graph.add_edge pygraph.classes.graph.graph-class.html#add_edge pygraph.classes.graph.graph.__eq__ pygraph.classes.graph.graph-class.html#__eq__ pygraph.mixins.labeling.labeling.del_node_labeling pygraph.mixins.labeling.labeling-class.html#del_node_labeling pygraph.mixins.common.common.add_graph pygraph.mixins.common.common-class.html#add_graph pygraph.mixins.common.common.reverse pygraph.mixins.common.common-class.html#reverse pygraph.mixins.labeling.labeling.LABEL_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#LABEL_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling.add_node_attribute pygraph.mixins.labeling.labeling-class.html#add_node_attribute pygraph.mixins.common.common.__repr__ pygraph.mixins.common.common-class.html#__repr__ pygraph.mixins.labeling.labeling.set_edge_weight pygraph.mixins.labeling.labeling-class.html#set_edge_weight pygraph.mixins.labeling.labeling.edge_weight pygraph.mixins.labeling.labeling-class.html#edge_weight pygraph.mixins.common.common.add_nodes pygraph.mixins.common.common-class.html#add_nodes pygraph.mixins.labeling.labeling.del_edge_labeling pygraph.mixins.labeling.labeling-class.html#del_edge_labeling pygraph.mixins.common.common.order pygraph.mixins.common.common-class.html#order pygraph.mixins.labeling.labeling.node_attributes pygraph.mixins.labeling.labeling-class.html#node_attributes pygraph.classes.hypergraph.hypergraph pygraph.classes.hypergraph.hypergraph-class.html pygraph.classes.hypergraph.hypergraph.neighbors pygraph.classes.hypergraph.hypergraph-class.html#neighbors pygraph.mixins.labeling.labeling.DEFAULT_WEIGHT pygraph.mixins.labeling.labeling-class.html#DEFAULT_WEIGHT pygraph.classes.hypergraph.hypergraph.links pygraph.classes.hypergraph.hypergraph-class.html#links pygraph.classes.hypergraph.hypergraph.add_node pygraph.classes.hypergraph.hypergraph-class.html#add_node pygraph.mixins.common.common.__str__ pygraph.mixins.common.common-class.html#__str__ pygraph.classes.hypergraph.hypergraph.has_edge pygraph.classes.hypergraph.hypergraph-class.html#has_edge pygraph.classes.hypergraph.hypergraph.rank pygraph.classes.hypergraph.hypergraph-class.html#rank pygraph.classes.hypergraph.hypergraph.del_edge pygraph.classes.hypergraph.hypergraph-class.html#del_edge pygraph.classes.hypergraph.hypergraph.del_node pygraph.classes.hypergraph.hypergraph-class.html#del_node pygraph.mixins.labeling.labeling.DEFAULT_LABEL pygraph.mixins.labeling.labeling-class.html#DEFAULT_LABEL pygraph.mixins.common.common.inverse pygraph.mixins.common.common-class.html#inverse pygraph.mixins.labeling.labeling.set_edge_properties pygraph.mixins.labeling.labeling-class.html#set_edge_properties pygraph.classes.hypergraph.hypergraph.has_hyperedge pygraph.classes.hypergraph.hypergraph-class.html#has_hyperedge pygraph.classes.hypergraph.hypergraph.__init__ pygraph.classes.hypergraph.hypergraph-class.html#__init__ pygraph.mixins.labeling.labeling.add_edge_attributes pygraph.mixins.labeling.labeling-class.html#add_edge_attributes pygraph.classes.hypergraph.hypergraph.DIRECTED pygraph.classes.hypergraph.hypergraph-class.html#DIRECTED pygraph.classes.hypergraph.hypergraph.add_edge pygraph.classes.hypergraph.hypergraph-class.html#add_edge pygraph.mixins.labeling.labeling.edge_label pygraph.mixins.labeling.labeling-class.html#edge_label pygraph.classes.hypergraph.hypergraph.add_hyperedge pygraph.classes.hypergraph.hypergraph-class.html#add_hyperedge pygraph.mixins.labeling.labeling.WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling.set_edge_label pygraph.mixins.labeling.labeling-class.html#set_edge_label pygraph.mixins.labeling.labeling.get_edge_properties pygraph.mixins.labeling.labeling-class.html#get_edge_properties pygraph.classes.hypergraph.hypergraph.nodes pygraph.classes.hypergraph.hypergraph-class.html#nodes pygraph.mixins.common.common.__len__ pygraph.mixins.common.common-class.html#__len__ pygraph.classes.hypergraph.hypergraph.__ne__ pygraph.classes.hypergraph.hypergraph-class.html#__ne__ pygraph.classes.hypergraph.hypergraph.add_edges pygraph.classes.hypergraph.hypergraph-class.html#add_edges pygraph.mixins.common.common.complete pygraph.mixins.common.common-class.html#complete pygraph.mixins.common.common.__getitem__ pygraph.mixins.common.common-class.html#__getitem__ pygraph.classes.hypergraph.hypergraph.has_node pygraph.classes.hypergraph.hypergraph-class.html#has_node pygraph.classes.hypergraph.hypergraph.del_hyperedge pygraph.classes.hypergraph.hypergraph-class.html#del_hyperedge pygraph.mixins.common.common.add_spanning_tree pygraph.mixins.common.common-class.html#add_spanning_tree pygraph.classes.hypergraph.hypergraph.add_hyperedges pygraph.classes.hypergraph.hypergraph-class.html#add_hyperedges pygraph.classes.hypergraph.hypergraph.edges pygraph.classes.hypergraph.hypergraph-class.html#edges pygraph.classes.hypergraph.hypergraph.link pygraph.classes.hypergraph.hypergraph-class.html#link pygraph.mixins.labeling.labeling.add_edge_attribute pygraph.mixins.labeling.labeling-class.html#add_edge_attribute pygraph.classes.hypergraph.hypergraph.unlink pygraph.classes.hypergraph.hypergraph-class.html#unlink pygraph.classes.hypergraph.hypergraph.__eq__ pygraph.classes.hypergraph.hypergraph-class.html#__eq__ pygraph.mixins.labeling.labeling.del_node_labeling pygraph.mixins.labeling.labeling-class.html#del_node_labeling pygraph.mixins.common.common.add_graph pygraph.mixins.common.common-class.html#add_graph pygraph.classes.hypergraph.hypergraph.hyperedges pygraph.classes.hypergraph.hypergraph-class.html#hyperedges pygraph.mixins.common.common.reverse pygraph.mixins.common.common-class.html#reverse pygraph.mixins.labeling.labeling.edge_attributes pygraph.mixins.labeling.labeling-class.html#edge_attributes pygraph.mixins.labeling.labeling.LABEL_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#LABEL_ATTRIBUTE_NAME pygraph.mixins.common.common.__iter__ pygraph.mixins.common.common-class.html#__iter__ pygraph.mixins.labeling.labeling.add_node_attribute pygraph.mixins.labeling.labeling-class.html#add_node_attribute pygraph.mixins.common.common.__repr__ pygraph.mixins.common.common-class.html#__repr__ pygraph.mixins.labeling.labeling.set_edge_weight pygraph.mixins.labeling.labeling-class.html#set_edge_weight pygraph.mixins.labeling.labeling.edge_weight pygraph.mixins.labeling.labeling-class.html#edge_weight pygraph.mixins.common.common.add_nodes pygraph.mixins.common.common-class.html#add_nodes pygraph.mixins.labeling.labeling.del_edge_labeling pygraph.mixins.labeling.labeling-class.html#del_edge_labeling pygraph.mixins.common.common.order pygraph.mixins.common.common-class.html#order pygraph.mixins.labeling.labeling.node_attributes pygraph.mixins.labeling.labeling-class.html#node_attributes pygraph.mixins.basegraph.basegraph pygraph.mixins.basegraph.basegraph-class.html pygraph.mixins.common.common pygraph.mixins.common.common-class.html pygraph.mixins.common.common.__str__ pygraph.mixins.common.common-class.html#__str__ pygraph.mixins.common.common.inverse pygraph.mixins.common.common-class.html#inverse pygraph.mixins.common.common.__len__ pygraph.mixins.common.common-class.html#__len__ pygraph.mixins.common.common.complete pygraph.mixins.common.common-class.html#complete pygraph.mixins.common.common.__getitem__ pygraph.mixins.common.common-class.html#__getitem__ pygraph.mixins.common.common.add_spanning_tree pygraph.mixins.common.common-class.html#add_spanning_tree pygraph.mixins.common.common.__iter__ pygraph.mixins.common.common-class.html#__iter__ pygraph.mixins.common.common.__eq__ pygraph.mixins.common.common-class.html#__eq__ pygraph.mixins.common.common.add_graph pygraph.mixins.common.common-class.html#add_graph pygraph.mixins.common.common.reverse pygraph.mixins.common.common-class.html#reverse pygraph.mixins.common.common.__repr__ pygraph.mixins.common.common-class.html#__repr__ pygraph.mixins.common.common.add_nodes pygraph.mixins.common.common-class.html#add_nodes pygraph.mixins.common.common.order pygraph.mixins.common.common-class.html#order pygraph.mixins.labeling.labeling pygraph.mixins.labeling.labeling-class.html pygraph.mixins.labeling.labeling.DEFAULT_WEIGHT pygraph.mixins.labeling.labeling-class.html#DEFAULT_WEIGHT pygraph.mixins.labeling.labeling.edge_attributes pygraph.mixins.labeling.labeling-class.html#edge_attributes pygraph.mixins.labeling.labeling.DEFAULT_LABEL pygraph.mixins.labeling.labeling-class.html#DEFAULT_LABEL pygraph.mixins.labeling.labeling.set_edge_properties pygraph.mixins.labeling.labeling-class.html#set_edge_properties pygraph.mixins.labeling.labeling.__init__ pygraph.mixins.labeling.labeling-class.html#__init__ pygraph.mixins.labeling.labeling.__eq__ pygraph.mixins.labeling.labeling-class.html#__eq__ pygraph.mixins.labeling.labeling.set_edge_label pygraph.mixins.labeling.labeling-class.html#set_edge_label pygraph.mixins.labeling.labeling.get_edge_properties pygraph.mixins.labeling.labeling-class.html#get_edge_properties pygraph.mixins.labeling.labeling.add_edge_attributes pygraph.mixins.labeling.labeling-class.html#add_edge_attributes pygraph.mixins.labeling.labeling.edge_label pygraph.mixins.labeling.labeling-class.html#edge_label pygraph.mixins.labeling.labeling.add_edge_attribute pygraph.mixins.labeling.labeling-class.html#add_edge_attribute pygraph.mixins.labeling.labeling.WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#WEIGHT_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling.LABEL_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling-class.html#LABEL_ATTRIBUTE_NAME pygraph.mixins.labeling.labeling.add_node_attribute pygraph.mixins.labeling.labeling-class.html#add_node_attribute pygraph.mixins.labeling.labeling.set_edge_weight pygraph.mixins.labeling.labeling-class.html#set_edge_weight pygraph.mixins.labeling.labeling.edge_weight pygraph.mixins.labeling.labeling-class.html#edge_weight pygraph.mixins.labeling.labeling.del_node_labeling pygraph.mixins.labeling.labeling-class.html#del_node_labeling pygraph.mixins.labeling.labeling.del_edge_labeling pygraph.mixins.labeling.labeling-class.html#del_edge_labeling pygraph.mixins.labeling.labeling.node_attributes pygraph.mixins.labeling.labeling-class.html#node_attributes python-graph-1.8.2/core/0000755000175000017500000000000012012025435014120 5ustar morphmorphpython-graph-1.8.2/core/setup.py0000755000175000017500000000220712000356031015632 0ustar morphmorph#!/usr/bin/env python # -*- coding: utf-8 -*- import os try: from setuptools import setup, find_packages except ImportError as ie: import distribute_setup distribute_setup.use_setuptools() from setuptools import setup, find_packages # Startup appname = "python-graph-core" appversion = "1.8.2" setup( name = appname, version = appversion, author = "Pedro Matiello", namespace_packages = ["pygraph"], packages = ["pygraph"] + [ os.path.join("pygraph", a) for a in find_packages("pygraph") ], author_email = "pmatiello@gmail.com", description = "A library for working with graphs in Python", license = "MIT", keywords = "python graphs hypergraphs networks library algorithms", url = "http://code.google.com/p/python-graph/", classifiers = ["License :: OSI Approved :: MIT License","Topic :: Software Development :: Libraries :: Python Modules"], long_description = "python-graph is a library for working with graphs in Python. This software provides a suitable data structure for representing graphs and a whole set of important algorithms.", ) python-graph-1.8.2/core/pygraph/0000755000175000017500000000000012012025435015572 5ustar morphmorphpython-graph-1.8.2/core/pygraph/readwrite/0000755000175000017500000000000012012025435017560 5ustar morphmorphpython-graph-1.8.2/core/pygraph/readwrite/markup.py0000644000175000017500000001525711663035302021450 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Functions for reading and writing graphs in a XML markup. @sort: read, read_hypergraph, write, write_hypergraph """ # Imports from pygraph.classes.digraph import digraph from pygraph.classes.exceptions import InvalidGraphType from pygraph.classes.graph import graph from pygraph.classes.hypergraph import hypergraph from xml.dom.minidom import Document, parseString def write(G): """ Return a string specifying the given graph as a XML document. @type G: graph @param G: Graph. @rtype: string @return: String specifying the graph as a XML document. """ # Document root grxml = Document() if (type(G) == graph): grxmlr = grxml.createElement('graph') elif (type(G) == digraph ): grxmlr = grxml.createElement('digraph') elif (type(G) == hypergraph ): return write_hypergraph(G) else: raise InvalidGraphType grxml.appendChild(grxmlr) # Each node... for each_node in G.nodes(): node = grxml.createElement('node') node.setAttribute('id', str(each_node)) grxmlr.appendChild(node) for each_attr in G.node_attributes(each_node): attr = grxml.createElement('attribute') attr.setAttribute('attr', each_attr[0]) attr.setAttribute('value', each_attr[1]) node.appendChild(attr) # Each edge... for edge_from, edge_to in G.edges(): edge = grxml.createElement('edge') edge.setAttribute('from', str(edge_from)) edge.setAttribute('to', str(edge_to)) edge.setAttribute('wt', str(G.edge_weight((edge_from, edge_to)))) edge.setAttribute('label', str(G.edge_label((edge_from, edge_to)))) grxmlr.appendChild(edge) for attr_name, attr_value in G.edge_attributes((edge_from, edge_to)): attr = grxml.createElement('attribute') attr.setAttribute('attr', attr_name) attr.setAttribute('value', attr_value) edge.appendChild(attr) return grxml.toprettyxml() def read(string): """ Read a graph from a XML document and return it. Nodes and edges specified in the input will be added to the current graph. @type string: string @param string: Input string in XML format specifying a graph. @rtype: graph @return: Graph """ dom = parseString(string) if dom.getElementsByTagName("graph"): G = graph() elif dom.getElementsByTagName("digraph"): G = digraph() elif dom.getElementsByTagName("hypergraph"): return read_hypergraph(string) else: raise InvalidGraphType # Read nodes... for each_node in dom.getElementsByTagName("node"): G.add_node(each_node.getAttribute('id')) for each_attr in each_node.getElementsByTagName("attribute"): G.add_node_attribute(each_node.getAttribute('id'), (each_attr.getAttribute('attr'), each_attr.getAttribute('value'))) # Read edges... for each_edge in dom.getElementsByTagName("edge"): if (not G.has_edge((each_edge.getAttribute('from'), each_edge.getAttribute('to')))): G.add_edge((each_edge.getAttribute('from'), each_edge.getAttribute('to')), \ wt = float(each_edge.getAttribute('wt')), label = each_edge.getAttribute('label')) for each_attr in each_edge.getElementsByTagName("attribute"): attr_tuple = (each_attr.getAttribute('attr'), each_attr.getAttribute('value')) if (attr_tuple not in G.edge_attributes((each_edge.getAttribute('from'), \ each_edge.getAttribute('to')))): G.add_edge_attribute((each_edge.getAttribute('from'), \ each_edge.getAttribute('to')), attr_tuple) return G def write_hypergraph(hgr): """ Return a string specifying the given hypergraph as a XML document. @type hgr: hypergraph @param hgr: Hypergraph. @rtype: string @return: String specifying the graph as a XML document. """ # Document root grxml = Document() grxmlr = grxml.createElement('hypergraph') grxml.appendChild(grxmlr) # Each node... nodes = hgr.nodes() hyperedges = hgr.hyperedges() for each_node in (nodes + hyperedges): if (each_node in nodes): node = grxml.createElement('node') else: node = grxml.createElement('hyperedge') node.setAttribute('id', str(each_node)) grxmlr.appendChild(node) # and its outgoing edge if each_node in nodes: for each_edge in hgr.links(each_node): edge = grxml.createElement('link') edge.setAttribute('to', str(each_edge)) node.appendChild(edge) return grxml.toprettyxml() def read_hypergraph(string): """ Read a graph from a XML document. Nodes and hyperedges specified in the input will be added to the current graph. @type string: string @param string: Input string in XML format specifying a graph. @rtype: hypergraph @return: Hypergraph """ hgr = hypergraph() dom = parseString(string) for each_node in dom.getElementsByTagName("node"): hgr.add_node(each_node.getAttribute('id')) for each_node in dom.getElementsByTagName("hyperedge"): hgr.add_hyperedge(each_node.getAttribute('id')) dom = parseString(string) for each_node in dom.getElementsByTagName("node"): for each_edge in each_node.getElementsByTagName("link"): hgr.link(str(each_node.getAttribute('id')), str(each_edge.getAttribute('to'))) return hgr python-graph-1.8.2/core/pygraph/readwrite/__init__.py0000644000175000017500000000235011242074006021673 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Readwrite algorithms. Algorithms for reading and writing graphs. """ __import__('pkg_resources').declare_namespace(__name__)python-graph-1.8.2/core/pygraph/mixins/0000755000175000017500000000000012012025435017101 5ustar morphmorphpython-graph-1.8.2/core/pygraph/mixins/labeling.py0000644000175000017500000001651211377117541021252 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. class labeling( object ): """ Generic labeling support for graphs @sort: __eq__, __init__, add_edge_attribute, add_edge_attributes, add_node_attribute, del_edge_labeling, del_node_labeling, edge_attributes, edge_label, edge_weight, get_edge_properties, node_attributes, set_edge_label, set_edge_properties, set_edge_weight """ WEIGHT_ATTRIBUTE_NAME = "weight" DEFAULT_WEIGHT = 1 LABEL_ATTRIBUTE_NAME = "label" DEFAULT_LABEL = "" def __init__(self): # Metadata bout edges self.edge_properties = {} # Mapping: Edge -> Dict mapping, lablel-> str, wt->num self.edge_attr = {} # Key value pairs: (Edge -> Attributes) # Metadata bout nodes self.node_attr = {} # Pairing: Node -> Attributes def del_node_labeling( self, node ): if node in self.node_attr: # Since attributes and properties are lazy, they might not exist. del( self.node_attr[node] ) def del_edge_labeling( self, edge ): keys = [edge] if not self.DIRECTED: keys.append(edge[::-1]) for key in keys: for mapping in [self.edge_properties, self.edge_attr ]: try: del ( mapping[key] ) except KeyError: pass def edge_weight(self, edge): """ Get the weight of an edge. @type edge: edge @param edge: One edge. @rtype: number @return: Edge weight. """ return self.get_edge_properties( edge ).setdefault( self.WEIGHT_ATTRIBUTE_NAME, self.DEFAULT_WEIGHT ) def set_edge_weight(self, edge, wt): """ Set the weight of an edge. @type edge: edge @param edge: One edge. @type wt: number @param wt: Edge weight. """ self.set_edge_properties(edge, weight=wt ) if not self.DIRECTED: self.set_edge_properties((edge[1], edge[0]) , weight=wt ) def edge_label(self, edge): """ Get the label of an edge. @type edge: edge @param edge: One edge. @rtype: string @return: Edge label """ return self.get_edge_properties( edge ).setdefault( self.LABEL_ATTRIBUTE_NAME, self.DEFAULT_LABEL ) def set_edge_label(self, edge, label): """ Set the label of an edge. @type edge: edge @param edge: One edge. @type label: string @param label: Edge label. """ self.set_edge_properties(edge, label=label ) if not self.DIRECTED: self.set_edge_properties((edge[1], edge[0]) , label=label ) def set_edge_properties(self, edge, **properties ): self.edge_properties.setdefault( edge, {} ).update( properties ) if (not self.DIRECTED and edge[0] != edge[1]): self.edge_properties.setdefault((edge[1], edge[0]), {}).update( properties ) def get_edge_properties(self, edge): return self.edge_properties.setdefault( edge, {} ) def add_edge_attribute(self, edge, attr): """ Add attribute to the given edge. @type edge: edge @param edge: One edge. @type attr: tuple @param attr: Node attribute specified as a tuple in the form (attribute, value). """ self.edge_attr[edge] = self.edge_attributes(edge) + [attr] if (not self.DIRECTED and edge[0] != edge[1]): self.edge_attr[(edge[1],edge[0])] = self.edge_attributes((edge[1], edge[0])) + [attr] def add_edge_attributes(self, edge, attrs): """ Append a sequence of attributes to the given edge @type edge: edge @param edge: One edge. @type attrs: tuple @param attrs: Node attributes specified as a sequence of tuples in the form (attribute, value). """ for attr in attrs: self.add_edge_attribute(edge, attr) def add_node_attribute(self, node, attr): """ Add attribute to the given node. @type node: node @param node: Node identifier @type attr: tuple @param attr: Node attribute specified as a tuple in the form (attribute, value). """ self.node_attr[node] = self.node_attr[node] + [attr] def node_attributes(self, node): """ Return the attributes of the given node. @type node: node @param node: Node identifier @rtype: list @return: List of attributes specified tuples in the form (attribute, value). """ return self.node_attr[node] def edge_attributes(self, edge): """ Return the attributes of the given edge. @type edge: edge @param edge: One edge. @rtype: list @return: List of attributes specified tuples in the form (attribute, value). """ try: return self.edge_attr[edge] except KeyError: return [] def __eq__(self, other): """ Return whether this graph is equal to another one. @type other: graph, digraph @param other: Other graph or digraph @rtype: boolean @return: Whether this graph and the other are equal. """ def attrs_eq(list1, list2): for each in list1: if (each not in list2): return False for each in list2: if (each not in list1): return False return True def edges_eq(): for edge in self.edges(): if (self.edge_weight(edge) != other.edge_weight(edge)): return False if (self.edge_label(edge) != other.edge_label(edge)): return False if (not attrs_eq(self.edge_attributes(edge), other.edge_attributes(edge))): return False return True def nodes_eq(): for node in self: if (not attrs_eq(self.node_attributes(node), other.node_attributes(node))): return False return True return nodes_eq() and edges_eq()python-graph-1.8.2/core/pygraph/mixins/common.py0000644000175000017500000001561211537413277020770 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. class common( object ): """ Standard methods common to all graph classes. @sort: __eq__, __getitem__, __iter__, __len__, __repr__, __str__, add_graph, add_nodes, add_spanning_tree, complete, inverse, order, reverse """ def __str__(self): """ Return a string representing the graph when requested by str() (or print). @rtype: string @return: String representing the graph. """ str_nodes = repr( self.nodes() ) str_edges = repr( self.edges() ) return "%s %s" % ( str_nodes, str_edges ) def __repr__(self): """ Return a string representing the graph when requested by repr() @rtype: string @return: String representing the graph. """ return "<%s.%s %s>" % ( self.__class__.__module__, self.__class__.__name__, str(self) ) def __iter__(self): """ Return a iterator passing through all nodes in the graph. @rtype: iterator @return: Iterator passing through all nodes in the graph. """ for n in self.nodes(): yield n def __len__(self): """ Return the order of self when requested by len(). @rtype: number @return: Size of the graph. """ return self.order() def __getitem__(self, node): """ Return a iterator passing through all neighbors of the given node. @rtype: iterator @return: Iterator passing through all neighbors of the given node. """ for n in self.neighbors( node ): yield n def order(self): """ Return the order of self, this is defined as the number of nodes in the graph. @rtype: number @return: Size of the graph. """ return len(self.nodes()) def add_nodes(self, nodelist): """ Add given nodes to the graph. @attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). Objects used to identify nodes absolutely must be hashable. If you need attach a mutable or non-hashable node, consider using the labeling feature. @type nodelist: list @param nodelist: List of nodes to be added to the graph. """ for each in nodelist: self.add_node(each) def add_graph(self, other): """ Add other graph to this graph. @attention: Attributes and labels are not preserved. @type other: graph @param other: Graph """ self.add_nodes( n for n in other.nodes() if not n in self.nodes() ) for each_node in other.nodes(): for each_edge in other.neighbors(each_node): if (not self.has_edge((each_node, each_edge))): self.add_edge((each_node, each_edge)) def add_spanning_tree(self, st): """ Add a spanning tree to the graph. @type st: dictionary @param st: Spanning tree. """ self.add_nodes(list(st.keys())) for each in st: if (st[each] is not None): self.add_edge((st[each], each)) def complete(self): """ Make the graph a complete graph. @attention: This will modify the current graph. """ for each in self.nodes(): for other in self.nodes(): if (each != other and not self.has_edge((each, other))): self.add_edge((each, other)) def inverse(self): """ Return the inverse of the graph. @rtype: graph @return: Complement graph for the graph. """ inv = self.__class__() inv.add_nodes(self.nodes()) inv.complete() for each in self.edges(): if (inv.has_edge(each)): inv.del_edge(each) return inv def reverse(self): """ Generate the reverse of a directed graph, returns an identical graph if not directed. Attributes & weights are preserved. @rtype: digraph @return: The directed graph that should be reversed. """ assert self.DIRECTED, "Undirected graph types such as %s cannot be reversed" % self.__class__.__name__ N = self.__class__() #- Add the nodes N.add_nodes( n for n in self.nodes() ) #- Add the reversed edges for (u, v) in self.edges(): wt = self.edge_weight((u, v)) label = self.edge_label((u, v)) attributes = self.edge_attributes((u, v)) N.add_edge((v, u), wt, label, attributes) return N def __eq__(self, other): """ Return whether this graph is equal to another one. @type other: graph, digraph @param other: Other graph or digraph @rtype: boolean @return: Whether this graph and the other are equal. """ def nodes_eq(): for each in self: if (not other.has_node(each)): return False for each in other: if (not self.has_node(each)): return False return True def edges_eq(): for edge in self.edges(): if (not other.has_edge(edge)): return False for edge in other.edges(): if (not self.has_edge(edge)): return False return True try: return nodes_eq() and edges_eq() except AttributeError: return False python-graph-1.8.2/core/pygraph/mixins/basegraph.py0000644000175000017500000000264111304255572021424 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. class basegraph( object ): """ An abstract class intended as a common ancestor to all graph classes. This allows the user to test isinstance(X, basegraph) to determine if the object is one of any of the python-graph main classes. """ python-graph-1.8.2/core/pygraph/mixins/__init__.py0000644000175000017500000000244011351243647021226 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Mixins. Base classes used to compose the the graph classes. The classes in this namespace should not be used directly. """ __import__('pkg_resources').declare_namespace(__name__) python-graph-1.8.2/core/pygraph/classes/0000755000175000017500000000000012012025435017227 5ustar morphmorphpython-graph-1.8.2/core/pygraph/classes/hypergraph.py0000644000175000017500000002522611532456371021776 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Anand Jeyahar # Christian Muise # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Hypergraph class """ # Imports from pygraph.classes.graph import graph from pygraph.classes.exceptions import AdditionError from pygraph.mixins.labeling import labeling from pygraph.mixins.common import common from pygraph.mixins.basegraph import basegraph class hypergraph (basegraph, common, labeling): """ Hypergraph class. Hypergraphs are a generalization of graphs where an edge (called hyperedge) can connect more than two nodes. @sort: __init__, __len__, __str__, add_hyperedge, add_hyperedges, add_node, add_nodes, del_edge, has_node, has_edge, has_hyperedge, hyperedges, link, links, nodes, unlink """ # Technically this isn't directed, but it gives us the right # behaviour with the parent classes. DIRECTED = True def __init__(self): """ Initialize a hypergraph. """ common.__init__(self) labeling.__init__(self) self.node_links = {} # Pairing: Node -> Hyperedge self.edge_links = {} # Pairing: Hyperedge -> Node self.graph = graph() # Ordinary graph def nodes(self): """ Return node list. @rtype: list @return: Node list. """ return list(self.node_links.keys()) def edges(self): """ Return the hyperedge list. @rtype: list @return: List of hyperedges in the graph. """ return self.hyperedges() def hyperedges(self): """ Return hyperedge list. @rtype: list @return: List of hyperedges in the graph. """ return list(self.edge_links.keys()) def has_edge(self, hyperedge): """ Return whether the requested node exists. @type hyperedge: hyperedge @param hyperedge: Hyperedge identifier @rtype: boolean @return: Truth-value for hyperedge existence. """ return self.has_hyperedge(hyperedge) def has_hyperedge(self, hyperedge): """ Return whether the requested node exists. @type hyperedge: hyperedge @param hyperedge: Hyperedge identifier @rtype: boolean @return: Truth-value for hyperedge existence. """ return hyperedge in self.edge_links def links(self, obj): """ Return all nodes connected by the given hyperedge or all hyperedges connected to the given hypernode. @type obj: hyperedge @param obj: Object identifier. @rtype: list @return: List of node objects linked to the given hyperedge. """ if obj in self.edge_links: return self.edge_links[obj] else: return self.node_links[obj] def neighbors(self, obj): """ Return all neighbors adjacent to the given node. @type obj: node @param obj: Object identifier. @rtype: list @return: List of all node objects adjacent to the given node. """ neighbors = set([]) for e in self.node_links[obj]: neighbors.update(set(self.edge_links[e])) return list(neighbors - set([obj])) def has_node(self, node): """ Return whether the requested node exists. @type node: node @param node: Node identifier @rtype: boolean @return: Truth-value for node existence. """ return node in self.node_links def add_node(self, node): """ Add given node to the hypergraph. @attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). @type node: node @param node: Node identifier. """ if (not node in self.node_links): self.node_links[node] = [] self.node_attr[node] = [] self.graph.add_node((node,'n')) else: raise AdditionError("Node %s already in graph" % node) def del_node(self, node): """ Delete a given node from the hypergraph. @type node: node @param node: Node identifier. """ if self.has_node(node): for e in self.node_links[node]: self.edge_links[e].remove(node) self.node_links.pop(node) self.graph.del_node((node,'n')) def add_edge(self, hyperedge): """ Add given hyperedge to the hypergraph. @attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). @type hyperedge: hyperedge @param hyperedge: Hyperedge identifier. """ self.add_hyperedge(hyperedge) def add_hyperedge(self, hyperedge): """ Add given hyperedge to the hypergraph. @attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). @type hyperedge: hyperedge @param hyperedge: Hyperedge identifier. """ if (not hyperedge in self.edge_links): self.edge_links[hyperedge] = [] self.graph.add_node((hyperedge,'h')) def add_edges(self, edgelist): """ Add given hyperedges to the hypergraph. @attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). @type edgelist: list @param edgelist: List of hyperedge-nodes to be added to the graph. """ self.add_hyperedges(edgelist) def add_hyperedges(self, edgelist): """ Add given hyperedges to the hypergraph. @attention: While hyperedge-nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). @type edgelist: list @param edgelist: List of hyperedge-nodes to be added to the graph. """ for each in edgelist: self.add_hyperedge(each) def del_edge(self, hyperedge): """ Delete the given hyperedge. @type hyperedge: hyperedge @param hyperedge: Hyperedge identifier. """ self.del_hyperedge(hyperedge) def del_hyperedge(self, hyperedge): """ Delete the given hyperedge. @type hyperedge: hyperedge @param hyperedge: Hyperedge identifier. """ if (hyperedge in self.hyperedges()): for n in self.edge_links[hyperedge]: self.node_links[n].remove(hyperedge) del(self.edge_links[hyperedge]) self.del_edge_labeling(hyperedge) self.graph.del_node((hyperedge,'h')) def link(self, node, hyperedge): """ Link given node and hyperedge. @type node: node @param node: Node. @type hyperedge: node @param hyperedge: Hyperedge. """ if (hyperedge not in self.node_links[node]): self.edge_links[hyperedge].append(node) self.node_links[node].append(hyperedge) self.graph.add_edge(((node,'n'), (hyperedge,'h'))) else: raise AdditionError("Link (%s, %s) already in graph" % (node, hyperedge)) def unlink(self, node, hyperedge): """ Unlink given node and hyperedge. @type node: node @param node: Node. @type hyperedge: hyperedge @param hyperedge: Hyperedge. """ self.node_links[node].remove(hyperedge) self.edge_links[hyperedge].remove(node) self.graph.del_edge(((node,'n'), (hyperedge,'h'))) def rank(self): """ Return the rank of the given hypergraph. @rtype: int @return: Rank of graph. """ max_rank = 0 for each in self.hyperedges(): if len(self.edge_links[each]) > max_rank: max_rank = len(self.edge_links[each]) return max_rank def __eq__(self, other): """ Return whether this hypergraph is equal to another one. @type other: hypergraph @param other: Other hypergraph @rtype: boolean @return: Whether this hypergraph and the other are equal. """ def links_eq(): for edge in self.edges(): for link in self.links(edge): if (link not in other.links(edge)): return False for edge in other.edges(): for link in other.links(edge): if (link not in self.links(edge)): return False return True return common.__eq__(self, other) and links_eq() and labeling.__eq__(self, other) def __ne__(self, other): """ Return whether this hypergraph is not equal to another one. @type other: hypergraph @param other: Other hypergraph @rtype: boolean @return: Whether this hypergraph and the other are different. """ return not (self == other)python-graph-1.8.2/core/pygraph/classes/graph.py0000644000175000017500000001516111550711445020717 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # Johannes Reinhardt # Nathan Davis # Zsolt Haraszti # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Graph class """ # Imports from pygraph.classes.exceptions import AdditionError from pygraph.mixins.labeling import labeling from pygraph.mixins.common import common from pygraph.mixins.basegraph import basegraph class graph(basegraph, common, labeling): """ Graph class. Graphs are built of nodes and edges. @sort: __eq__, __init__, __ne__, add_edge, add_node, del_edge, del_node, edges, has_edge, has_node, neighbors, node_order, nodes """ DIRECTED = False def __init__(self): """ Initialize a graph. """ common.__init__(self) labeling.__init__(self) self.node_neighbors = {} # Pairing: Node -> Neighbors def nodes(self): """ Return node list. @rtype: list @return: Node list. """ return list(self.node_neighbors.keys()) def neighbors(self, node): """ Return all nodes that are directly accessible from given node. @type node: node @param node: Node identifier @rtype: list @return: List of nodes directly accessible from given node. """ return self.node_neighbors[node] def edges(self): """ Return all edges in the graph. @rtype: list @return: List of all edges in the graph. """ return [ a for a in self.edge_properties.keys() ] def has_node(self, node): """ Return whether the requested node exists. @type node: node @param node: Node identifier @rtype: boolean @return: Truth-value for node existence. """ return node in self.node_neighbors def add_node(self, node, attrs=None): """ Add given node to the graph. @attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). @type node: node @param node: Node identifier. @type attrs: list @param attrs: List of node attributes specified as (attribute, value) tuples. """ if attrs is None: attrs = [] if (not node in self.node_neighbors): self.node_neighbors[node] = [] self.node_attr[node] = attrs else: raise AdditionError("Node %s already in graph" % node) def add_edge(self, edge, wt=1, label='', attrs=[]): """ Add an edge to the graph connecting two nodes. An edge, here, is a pair of nodes like C{(n, m)}. @type edge: tuple @param edge: Edge. @type wt: number @param wt: Edge weight. @type label: string @param label: Edge label. @type attrs: list @param attrs: List of node attributes specified as (attribute, value) tuples. """ u, v = edge if (v not in self.node_neighbors[u] and u not in self.node_neighbors[v]): self.node_neighbors[u].append(v) if (u != v): self.node_neighbors[v].append(u) self.add_edge_attributes((u,v), attrs) self.set_edge_properties((u, v), label=label, weight=wt) else: raise AdditionError("Edge (%s, %s) already in graph" % (u, v)) def del_node(self, node): """ Remove a node from the graph. @type node: node @param node: Node identifier. """ for each in list(self.neighbors(node)): if (each != node): self.del_edge((each, node)) del(self.node_neighbors[node]) del(self.node_attr[node]) def del_edge(self, edge): """ Remove an edge from the graph. @type edge: tuple @param edge: Edge. """ u, v = edge self.node_neighbors[u].remove(v) self.del_edge_labeling((u, v)) if (u != v): self.node_neighbors[v].remove(u) self.del_edge_labeling((v, u)) # TODO: This is redundant def has_edge(self, edge): """ Return whether an edge exists. @type edge: tuple @param edge: Edge. @rtype: boolean @return: Truth-value for edge existence. """ u,v = edge return (u,v) in self.edge_properties and (v,u) in self.edge_properties def node_order(self, node): """ Return the order of the graph @rtype: number @return: Order of the given node. """ return len(self.neighbors(node)) def __eq__(self, other): """ Return whether this graph is equal to another one. @type other: graph, digraph @param other: Other graph or digraph @rtype: boolean @return: Whether this graph and the other are equal. """ return common.__eq__(self, other) and labeling.__eq__(self, other) def __ne__(self, other): """ Return whether this graph is not equal to another one. @type other: graph, digraph @param other: Other graph or digraph @rtype: boolean @return: Whether this graph and the other are different. """ return not (self == other) python-graph-1.8.2/core/pygraph/classes/exceptions.py0000644000175000017500000000450311341330500021760 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Exceptions. """ # Graph errors class GraphError(RuntimeError): """ A base-class for the various kinds of errors that occur in the the python-graph class. """ pass class AdditionError(GraphError): """ This error is raised when trying to add a node or edge already added to the graph or digraph. """ pass class NodeUnreachable(GraphError): """ Goal could not be reached from start. """ def __init__(self, start, goal): msg = "Node %s could not be reached from node %s" % ( repr(goal), repr(start) ) InvalidGraphType.__init__(self, msg) self.start = start self.goal = goal class InvalidGraphType(GraphError): """ Invalid graph type. """ pass # Algorithm errors class AlgorithmError(RuntimeError): """ A base-class for the various kinds of errors that occur in the the algorithms package. """ pass class NegativeWeightCycleError(AlgorithmError): """ Algorithms like the Bellman-Ford algorithm can detect and raise an exception when they encounter a negative weight cycle. @see: pygraph.algorithms.shortest_path_bellman_ford """ pass python-graph-1.8.2/core/pygraph/classes/digraph.py0000644000175000017500000001753111550711445021237 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # Christian Muise # Johannes Reinhardt # Nathan Davis # Zsolt Haraszti # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Digraph class """ # Imports from pygraph.classes.exceptions import AdditionError from pygraph.mixins.labeling import labeling from pygraph.mixins.common import common from pygraph.mixins.basegraph import basegraph class digraph (basegraph, common, labeling): """ Digraph class. Digraphs are built of nodes and directed edges. @sort: __eq__, __init__, __ne__, add_edge, add_node, del_edge, del_node, edges, has_edge, has_node, incidents, neighbors, node_order, nodes """ DIRECTED = True def __init__(self): """ Initialize a digraph. """ common.__init__(self) labeling.__init__(self) self.node_neighbors = {} # Pairing: Node -> Neighbors self.node_incidence = {} # Pairing: Node -> Incident nodes def nodes(self): """ Return node list. @rtype: list @return: Node list. """ return list(self.node_neighbors.keys()) def neighbors(self, node): """ Return all nodes that are directly accessible from given node. @type node: node @param node: Node identifier @rtype: list @return: List of nodes directly accessible from given node. """ return self.node_neighbors[node] def incidents(self, node): """ Return all nodes that are incident to the given node. @type node: node @param node: Node identifier @rtype: list @return: List of nodes directly accessible from given node. """ return self.node_incidence[node] def edges(self): """ Return all edges in the graph. @rtype: list @return: List of all edges in the graph. """ return [ a for a in self._edges() ] def _edges(self): for n, neighbors in self.node_neighbors.items(): for neighbor in neighbors: yield (n, neighbor) def has_node(self, node): """ Return whether the requested node exists. @type node: node @param node: Node identifier @rtype: boolean @return: Truth-value for node existence. """ return node in self.node_neighbors def add_node(self, node, attrs = None): """ Add given node to the graph. @attention: While nodes can be of any type, it's strongly recommended to use only numbers and single-line strings as node identifiers if you intend to use write(). @type node: node @param node: Node identifier. @type attrs: list @param attrs: List of node attributes specified as (attribute, value) tuples. """ if attrs is None: attrs = [] if (node not in self.node_neighbors): self.node_neighbors[node] = [] self.node_incidence[node] = [] self.node_attr[node] = attrs else: raise AdditionError("Node %s already in digraph" % node) def add_edge(self, edge, wt = 1, label="", attrs = []): """ Add an directed edge to the graph connecting two nodes. An edge, here, is a pair of nodes like C{(n, m)}. @type edge: tuple @param edge: Edge. @type wt: number @param wt: Edge weight. @type label: string @param label: Edge label. @type attrs: list @param attrs: List of node attributes specified as (attribute, value) tuples. """ u, v = edge for n in [u,v]: if not n in self.node_neighbors: raise AdditionError( "%s is missing from the node_neighbors table" % n ) if not n in self.node_incidence: raise AdditionError( "%s is missing from the node_incidence table" % n ) if v in self.node_neighbors[u] and u in self.node_incidence[v]: raise AdditionError("Edge (%s, %s) already in digraph" % (u, v)) else: self.node_neighbors[u].append(v) self.node_incidence[v].append(u) self.set_edge_weight((u, v), wt) self.add_edge_attributes( (u, v), attrs ) self.set_edge_properties( (u, v), label=label, weight=wt ) def del_node(self, node): """ Remove a node from the graph. @type node: node @param node: Node identifier. """ for each in list(self.incidents(node)): # Delete all the edges incident on this node self.del_edge((each, node)) for each in list(self.neighbors(node)): # Delete all the edges pointing to this node. self.del_edge((node, each)) # Remove this node from the neighbors and incidents tables del(self.node_neighbors[node]) del(self.node_incidence[node]) # Remove any labeling which may exist. self.del_node_labeling( node ) def del_edge(self, edge): """ Remove an directed edge from the graph. @type edge: tuple @param edge: Edge. """ u, v = edge self.node_neighbors[u].remove(v) self.node_incidence[v].remove(u) self.del_edge_labeling( (u,v) ) def has_edge(self, edge): """ Return whether an edge exists. @type edge: tuple @param edge: Edge. @rtype: boolean @return: Truth-value for edge existence. """ u, v = edge return (u, v) in self.edge_properties def node_order(self, node): """ Return the order of the given node. @rtype: number @return: Order of the given node. """ return len(self.neighbors(node)) def __eq__(self, other): """ Return whether this graph is equal to another one. @type other: graph, digraph @param other: Other graph or digraph @rtype: boolean @return: Whether this graph and the other are equal. """ return common.__eq__(self, other) and labeling.__eq__(self, other) def __ne__(self, other): """ Return whether this graph is not equal to another one. @type other: graph, digraph @param other: Other graph or digraph @rtype: boolean @return: Whether this graph and the other are different. """ return not (self == other) python-graph-1.8.2/core/pygraph/classes/__init__.py0000644000175000017500000000220511260750275021352 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Data structure classes. """python-graph-1.8.2/core/pygraph/algorithms/0000755000175000017500000000000012012025435017743 5ustar morphmorphpython-graph-1.8.2/core/pygraph/algorithms/utils.py0000644000175000017500000000522111242044443021461 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Roy Smith # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Miscellaneous useful stuff. """ # Imports from heapq import heappush, heappop, heapify # Priority Queue class priority_queue: """ Priority queue. """ def __init__(self, list=[]): self.heap = [HeapItem(i, 0) for i in list] heapify(self.heap) def __contains__(self, item): for heap_item in self.heap: if item == heap_item.item: return True return False def __len__(self): return len(self.heap) def empty(self): return len(self.heap) == 0 def insert(self, item, priority): """ Insert item into the queue, with the given priority. """ heappush(self.heap, HeapItem(item, priority)) def pop(self): """ Return the item with the lowest priority, and remove it from the queue. """ return heappop(self.heap).item def peek(self): """ Return the item with the lowest priority. The queue is unchanged. """ return self.heap[0].item def discard(self, item): new_heap = [] for heap_item in self.heap: if item != heap_item.item: new_heap.append(heap_item) self.heap = new_heap heapify(self.heap) class HeapItem: def __init__(self, item, priority): self.item = item self.priority = priority def __cmp__(self, other): return cmp(self.priority, other.priority) python-graph-1.8.2/core/pygraph/algorithms/traversal.py0000644000175000017500000000462511406535144022340 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Traversal algorithms. @sort: traversal """ # Minimal spanning tree def traversal(graph, node, order): """ Graph traversal iterator. @type graph: graph, digraph @param graph: Graph. @type node: node @param node: Node. @type order: string @param order: traversal ordering. Possible values are: 2. 'pre' - Preordering (default) 1. 'post' - Postordering @rtype: iterator @return: Traversal iterator. """ visited = {} if (order == 'pre'): pre = 1 post = 0 elif (order == 'post'): pre = 0 post = 1 for each in _dfs(graph, visited, node, pre, post): yield each def _dfs(graph, visited, node, pre, post): """ Depth-first search subfunction for traversals. @type graph: graph, digraph @param graph: Graph. @type visited: dictionary @param visited: List of nodes (visited nodes are marked non-zero). @type node: node @param node: Node to be explored by DFS. """ visited[node] = 1 if (pre): yield node # Explore recursively the connected component for each in graph[node]: if (each not in visited): for other in _dfs(graph, visited, each, pre, post): yield other if (post): yield node python-graph-1.8.2/core/pygraph/algorithms/sorting.py0000644000175000017500000000326211276036623022021 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Sorting algorithms. @sort: topological_sorting """ # Imports from pygraph.algorithms.searching import depth_first_search # Topological sorting def topological_sorting(graph): """ Topological sorting. @attention: Topological sorting is meaningful only for directed acyclic graphs. @type graph: digraph @param graph: Graph. @rtype: list @return: Topological sorting for the graph. """ # The topological sorting of a DAG is equivalent to its reverse postordering. order = depth_first_search(graph)[2] order.reverse() return order python-graph-1.8.2/core/pygraph/algorithms/searching.py0000644000175000017500000001103711345305503022267 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Search algorithms. @sort: breadth_first_search, depth_first_search """ # Imports from pygraph.algorithms.filters.null import null from sys import getrecursionlimit, setrecursionlimit # Depth-first search def depth_first_search(graph, root=None, filter=null()): """ Depth-first search. @type graph: graph, digraph @param graph: Graph. @type root: node @param root: Optional root node (will explore only root's connected component) @rtype: tuple @return: A tupple containing a dictionary and two lists: 1. Generated spanning tree 2. Graph's preordering 3. Graph's postordering """ recursionlimit = getrecursionlimit() setrecursionlimit(max(len(graph.nodes())*2,recursionlimit)) def dfs(node): """ Depth-first search subfunction. """ visited[node] = 1 pre.append(node) # Explore recursively the connected component for each in graph[node]: if (each not in visited and filter(each, node)): spanning_tree[each] = node dfs(each) post.append(node) visited = {} # List for marking visited and non-visited nodes spanning_tree = {} # Spanning tree pre = [] # Graph's preordering post = [] # Graph's postordering filter.configure(graph, spanning_tree) # DFS from one node only if (root is not None): if filter(root, None): spanning_tree[root] = None dfs(root) setrecursionlimit(recursionlimit) return spanning_tree, pre, post # Algorithm loop for each in graph: # Select a non-visited node if (each not in visited and filter(each, None)): spanning_tree[each] = None # Explore node's connected component dfs(each) setrecursionlimit(recursionlimit) return (spanning_tree, pre, post) # Breadth-first search def breadth_first_search(graph, root=None, filter=null()): """ Breadth-first search. @type graph: graph, digraph @param graph: Graph. @type root: node @param root: Optional root node (will explore only root's connected component) @rtype: tuple @return: A tuple containing a dictionary and a list. 1. Generated spanning tree 2. Graph's level-based ordering """ def bfs(): """ Breadth-first search subfunction. """ while (queue != []): node = queue.pop(0) for other in graph[node]: if (other not in spanning_tree and filter(other, node)): queue.append(other) ordering.append(other) spanning_tree[other] = node queue = [] # Visiting queue spanning_tree = {} # Spanning tree ordering = [] filter.configure(graph, spanning_tree) # BFS from one node only if (root is not None): if filter(root, None): queue.append(root) ordering.append(root) spanning_tree[root] = None bfs() return spanning_tree, ordering # Algorithm for each in graph: if (each not in spanning_tree): if filter(each, None): queue.append(each) ordering.append(each) spanning_tree[each] = None bfs() return spanning_tree, ordering python-graph-1.8.2/core/pygraph/algorithms/pagerank.py0000644000175000017500000000523411521070317022114 0ustar morphmorph# Copyright (c) 2010 Pedro Matiello # Juarez Bochi # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ PageRank algoritm @sort: pagerank """ def pagerank(graph, damping_factor=0.85, max_iterations=100, min_delta=0.00001): """ Compute and return the PageRank in an directed graph. @type graph: digraph @param graph: Digraph. @type damping_factor: number @param damping_factor: PageRank dumping factor. @type max_iterations: number @param max_iterations: Maximum number of iterations. @type min_delta: number @param min_delta: Smallest variation required to have a new iteration. @rtype: Dict @return: Dict containing all the nodes PageRank. """ nodes = graph.nodes() graph_size = len(nodes) if graph_size == 0: return {} min_value = (1.0-damping_factor)/graph_size #value for nodes without inbound links # itialize the page rank dict with 1/N for all nodes pagerank = dict.fromkeys(nodes, 1.0/graph_size) for i in range(max_iterations): diff = 0 #total difference compared to last iteraction # computes each node PageRank based on inbound links for node in nodes: rank = min_value for referring_page in graph.incidents(node): rank += damping_factor * pagerank[referring_page] / len(graph.neighbors(referring_page)) diff += abs(pagerank[node] - rank) pagerank[node] = rank #stop if PageRank has converged if diff < min_delta: break return pagerank python-graph-1.8.2/core/pygraph/algorithms/minmax.py0000644000175000017500000003732111677601557021641 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # Peter Sagerson # Johannes Reinhardt # Rhys Ulerich # Roy Smith # Salim Fadhley # Tomaz Kovacic # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Minimization and maximization algorithms. @sort: heuristic_search, minimal_spanning_tree, shortest_path, shortest_path_bellman_ford """ from pygraph.algorithms.utils import heappush, heappop from pygraph.classes.exceptions import NodeUnreachable from pygraph.classes.exceptions import NegativeWeightCycleError from pygraph.classes.digraph import digraph import bisect # Minimal spanning tree def minimal_spanning_tree(graph, root=None): """ Minimal spanning tree. @attention: Minimal spanning tree is meaningful only for weighted graphs. @type graph: graph @param graph: Graph. @type root: node @param root: Optional root node (will explore only root's connected component) @rtype: dictionary @return: Generated spanning tree. """ visited = [] # List for marking visited and non-visited nodes spanning_tree = {} # MInimal Spanning tree # Initialization if (root is not None): visited.append(root) nroot = root spanning_tree[root] = None else: nroot = 1 # Algorithm loop while (nroot is not None): ledge = _lightest_edge(graph, visited) if (ledge == None): if (root is not None): break nroot = _first_unvisited(graph, visited) if (nroot is not None): spanning_tree[nroot] = None visited.append(nroot) else: spanning_tree[ledge[1]] = ledge[0] visited.append(ledge[1]) return spanning_tree def _first_unvisited(graph, visited): """ Return first unvisited node. @type graph: graph @param graph: Graph. @type visited: list @param visited: List of nodes. @rtype: node @return: First unvisited node. """ for each in graph: if (each not in visited): return each return None def _lightest_edge(graph, visited): """ Return the lightest edge in graph going from a visited node to an unvisited one. @type graph: graph @param graph: Graph. @type visited: list @param visited: List of nodes. @rtype: tuple @return: Lightest edge in graph going from a visited node to an unvisited one. """ lightest_edge = None weight = None for each in visited: for other in graph[each]: if (other not in visited): w = graph.edge_weight((each, other)) if (weight is None or w < weight or weight < 0): lightest_edge = (each, other) weight = w return lightest_edge # Shortest Path def shortest_path(graph, source): """ Return the shortest path distance between source and all other nodes using Dijkstra's algorithm. @attention: All weights must be nonnegative. @see: shortest_path_bellman_ford @type graph: graph, digraph @param graph: Graph. @type source: node @param source: Node from which to start the search. @rtype: tuple @return: A tuple containing two dictionaries, each keyed by target nodes. 1. Shortest path spanning tree 2. Shortest distance from given source to each target node Inaccessible target nodes do not appear in either dictionary. """ # Initialization dist = {source: 0} previous = {source: None} # This is a sorted queue of (dist, node) 2-tuples. The first item in the # queue is always either a finalized node that we can ignore or the node # with the smallest estimated distance from the source. Note that we will # not remove nodes from this list as they are finalized; we just ignore them # when they come up. q = [(0, source)] # The set of nodes for which we have final distances. finished = set() # Algorithm loop while len(q) > 0: du, u = q.pop(0) # Process reachable, remaining nodes from u if u not in finished: finished.add(u) for v in graph[u]: if v not in finished: alt = du + graph.edge_weight((u, v)) if (v not in dist) or (alt < dist[v]): dist[v] = alt previous[v] = u bisect.insort(q, (alt, v)) return previous, dist def shortest_path_bellman_ford(graph, source): """ Return the shortest path distance between the source node and all other nodes in the graph using Bellman-Ford's algorithm. This algorithm is useful when you have a weighted (and obviously a directed) graph with negative weights. @attention: The algorithm can detect negative weight cycles and will raise an exception. It's meaningful only for directed weighted graphs. @see: shortest_path @type graph: digraph @param graph: Digraph @type source: node @param source: Source node of the graph @raise NegativeWeightCycleError: raises if it finds a negative weight cycle. If this condition is met d(v) > d(u) + W(u, v) then raise the error. @rtype: tuple @return: A tuple containing two dictionaries, each keyed by target nodes. (same as shortest_path function that implements Dijkstra's algorithm) 1. Shortest path spanning tree 2. Shortest distance from given source to each target node """ # initialize the required data structures distance = {source : 0} predecessor = {source : None} # iterate and relax edges for i in range(1,graph.order()-1): for src,dst in graph.edges(): if (src in distance) and (dst not in distance): distance[dst] = distance[src] + graph.edge_weight((src,dst)) predecessor[dst] = src elif (src in distance) and (dst in distance) and \ distance[src] + graph.edge_weight((src,dst)) < distance[dst]: distance[dst] = distance[src] + graph.edge_weight((src,dst)) predecessor[dst] = src # detect negative weight cycles for src,dst in graph.edges(): if src in distance and \ dst in distance and \ distance[src] + graph.edge_weight((src,dst)) < distance[dst]: raise NegativeWeightCycleError("Detected a negative weight cycle on edge (%s, %s)" % (src,dst)) return predecessor, distance #Heuristics search def heuristic_search(graph, start, goal, heuristic): """ A* search algorithm. A set of heuristics is available under C{graph.algorithms.heuristics}. User-created heuristics are allowed too. @type graph: graph, digraph @param graph: Graph @type start: node @param start: Start node @type goal: node @param goal: Goal node @type heuristic: function @param heuristic: Heuristic function @rtype: list @return: Optimized path from start to goal node """ # The queue stores priority, node, cost to reach, and parent. queue = [ (0, start, 0, None) ] # This dictionary maps queued nodes to distance of discovered paths # and the computed heuristics to goal. We avoid to compute the heuristics # more than once and to insert too many times the node in the queue. g = {} # This maps explored nodes to parent closest to the start explored = {} while queue: _, current, dist, parent = heappop(queue) if current == goal: path = [current] + [ n for n in _reconstruct_path( parent, explored ) ] path.reverse() return path if current in explored: continue explored[current] = parent for neighbor in graph[current]: if neighbor in explored: continue ncost = dist + graph.edge_weight((current, neighbor)) if neighbor in g: qcost, h = g[neighbor] if qcost <= ncost: continue # if ncost < qcost, a longer path to neighbor remains # g. Removing it would need to filter the whole # queue, it's better just to leave it there and ignore # it when we visit the node a second time. else: h = heuristic(neighbor, goal) g[neighbor] = ncost, h heappush(queue, (ncost + h, neighbor, ncost, current)) raise NodeUnreachable( start, goal ) def _reconstruct_path(node, parents): while node is not None: yield node node = parents[node] #maximum flow/minimum cut def maximum_flow(graph, source, sink, caps = None): """ Find a maximum flow and minimum cut of a directed graph by the Edmonds-Karp algorithm. @type graph: digraph @param graph: Graph @type source: node @param source: Source of the flow @type sink: node @param sink: Sink of the flow @type caps: dictionary @param caps: Dictionary specifying a maximum capacity for each edge. If not given, the weight of the edge will be used as its capacity. Otherwise, for each edge (a,b), caps[(a,b)] should be given. @rtype: tuple @return: A tuple containing two dictionaries 1. contains the flow through each edge for a maximal flow through the graph 2. contains to which component of a minimum cut each node belongs """ #handle optional argument, if weights are available, use them, if not, assume one if caps == None: caps = {} for edge in graph.edges(): caps[edge] = graph.edge_weight((edge[0],edge[1])) #data structures to maintain f = {}.fromkeys(graph.edges(),0) label = {}.fromkeys(graph.nodes(),[]) label[source] = ['-',float('Inf')] u = {}.fromkeys(graph.nodes(),False) d = {}.fromkeys(graph.nodes(),float('Inf')) #queue for labelling q = [source] finished = False while not finished: #choose first labelled vertex with u == false for i in range(len(q)): if not u[q[i]]: v = q.pop(i) break #find augmenting path for w in graph.neighbors(v): if label[w] == [] and f[(v,w)] < caps[(v,w)]: d[w] = min(caps[(v,w)] - f[(v,w)],d[v]) label[w] = [v,'+',d[w]] q.append(w) for w in graph.incidents(v): if label[w] == [] and f[(w,v)] > 0: d[w] = min(f[(w,v)],d[v]) label[w] = [v,'-',d[w]] q.append(w) u[v] = True #extend flow by augmenting path if label[sink] != []: delta = label[sink][-1] w = sink while w != source: v = label[w][0] if label[w][1] == '-': f[(w,v)] = f[(w,v)] - delta else: f[(v,w)] = f[(v,w)] + delta w = v #reset labels label = {}.fromkeys(graph.nodes(),[]) label[source] = ['-',float('Inf')] q = [source] u = {}.fromkeys(graph.nodes(),False) d = {}.fromkeys(graph.nodes(),float('Inf')) #check whether finished finished = True for node in graph.nodes(): if label[node] != [] and u[node] == False: finished = False #find the two components of the cut cut = {} for node in graph.nodes(): if label[node] == []: cut[node] = 1 else: cut[node] = 0 return (f,cut) def cut_value(graph, flow, cut): """ Calculate the value of a cut. @type graph: digraph @param graph: Graph @type flow: dictionary @param flow: Dictionary containing a flow for each edge. @type cut: dictionary @param cut: Dictionary mapping each node to a subset index. The function only considers the flow between nodes with 0 and 1. @rtype: float @return: The value of the flow between the subsets 0 and 1 """ #max flow/min cut value calculation S = [] T = [] for node in cut.keys(): if cut[node] == 0: S.append(node) elif cut[node] == 1: T.append(node) value = 0 for node in S: for neigh in graph.neighbors(node): if neigh in T: value = value + flow[(node,neigh)] for inc in graph.incidents(node): if inc in T: value = value - flow[(inc,node)] return value def cut_tree(igraph, caps = None): """ Construct a Gomory-Hu cut tree by applying the algorithm of Gusfield. @type igraph: graph @param igraph: Graph @type caps: dictionary @param caps: Dictionary specifying a maximum capacity for each edge. If not given, the weight of the edge will be used as its capacity. Otherwise, for each edge (a,b), caps[(a,b)] should be given. @rtype: dictionary @return: Gomory-Hu cut tree as a dictionary, where each edge is associated with its weight """ #maximum flow needs a digraph, we get a graph #I think this conversion relies on implementation details outside the api and may break in the future graph = digraph() graph.add_graph(igraph) #handle optional argument if not caps: caps = {} for edge in graph.edges(): caps[edge] = igraph.edge_weight(edge) #temporary flow variable f = {} #we use a numbering of the nodes for easier handling n = {} N = 0 for node in graph.nodes(): n[N] = node N = N + 1 #predecessor function p = {}.fromkeys(range(N),0) p[0] = None for s in range(1,N): t = p[s] S = [] #max flow calculation (flow,cut) = maximum_flow(graph,n[s],n[t],caps) for i in range(N): if cut[n[i]] == 0: S.append(i) value = cut_value(graph,flow,cut) f[s] = value for i in range(N): if i == s: continue if i in S and p[i] == t: p[i] = s if p[t] in S: p[s] = p[t] p[t] = s f[s] = f[t] f[t] = value #cut tree is a dictionary, where each edge is associated with its weight b = {} for i in range(1,N): b[(n[i],n[p[i]])] = f[i] return b python-graph-1.8.2/core/pygraph/algorithms/heuristics/0000755000175000017500000000000012012025435022125 5ustar morphmorphpython-graph-1.8.2/core/pygraph/algorithms/heuristics/euclidean.py0000644000175000017500000000660211274657127024456 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ A* heuristic for euclidean graphs. """ # Imports class euclidean(object): """ A* heuristic for Euclidean graphs. This heuristic has three requirements: 1. All nodes should have the attribute 'position'; 2. The weight of all edges should be the euclidean distance between the nodes it links; 3. The C{optimize()} method should be called before the heuristic search. A small example for clarification: >>> g = graph.graph() >>> g.add_nodes(['A','B','C']) >>> g.add_node_attribute('A', ('position',(0,0))) >>> g.add_node_attribute('B', ('position',(1,1))) >>> g.add_node_attribute('C', ('position',(0,2))) >>> g.add_edge('A','B', wt=2) >>> g.add_edge('B','C', wt=2) >>> g.add_edge('A','C', wt=4) >>> h = graph.heuristics.euclidean() >>> h.optimize(g) >>> g.heuristic_search('A', 'C', h) """ def __init__(self): """ Initialize the heuristic object. """ self.distances = {} def optimize(self, graph): """ Build a dictionary mapping each pair of nodes to a number (the distance between them). @type graph: graph @param graph: Graph. """ for start in graph.nodes(): for end in graph.nodes(): for each in graph.node_attributes(start): if (each[0] == 'position'): start_attr = each[1] break for each in graph.node_attributes(end): if (each[0] == 'position'): end_attr = each[1] break dist = 0 for i in range(len(start_attr)): dist = dist + (float(start_attr[i]) - float(end_attr[i]))**2 self.distances[(start,end)] = dist def __call__(self, start, end): """ Estimate how far start is from end. @type start: node @param start: Start node. @type end: node @param end: End node. """ assert len(list(self.distances.keys())) > 0, "You need to optimize this heuristic for your graph before it can be used to estimate." return self.distances[(start,end)]python-graph-1.8.2/core/pygraph/algorithms/heuristics/chow.py0000644000175000017500000000527511274657127023472 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Edmond Chow's heuristic for A*. """ # Imports from pygraph.algorithms.minmax import shortest_path class chow(object): """ An implementation of the graph searching heuristic proposed by Edmond Chow. Remember to call the C{optimize()} method before the heuristic search. For details, check: U{http://www.edmondchow.com/pubs/levdiff-aaai.pdf}. """ def __init__(self, *centers): """ Initialize a Chow heuristic object. """ self.centers = centers self.nodes = {} def optimize(self, graph): """ Build a dictionary mapping each pair of nodes to a number (the distance between them). @type graph: graph @param graph: Graph. """ for center in self.centers: shortest_routes = shortest_path(graph, center)[1] for node, weight in list(shortest_routes.items()): self.nodes.setdefault(node, []).append(weight) def __call__(self, start, end): """ Estimate how far start is from end. @type start: node @param start: Start node. @type end: node @param end: End node. """ assert len( list(self.nodes.keys()) ) > 0, "You need to optimize this heuristic for your graph before it can be used to estimate." cmp_sequence = list(zip( self.nodes[start], self.nodes[end] )) chow_number = max( abs( a-b ) for a,b in cmp_sequence ) return chow_number python-graph-1.8.2/core/pygraph/algorithms/heuristics/__init__.py0000644000175000017500000000247111260747672024264 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Salim Fadhley # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Set of search heuristics. These are to be used with the C{heuristic_search()} function. """ __import__('pkg_resources').declare_namespace(__name__) python-graph-1.8.2/core/pygraph/algorithms/generators.py0000644000175000017500000000745411504663631022513 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # Zsolt Haraszti # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Random graph generators. @sort: generate, generate_hypergraph """ # Imports from pygraph.classes.graph import graph from pygraph.classes.digraph import digraph from pygraph.classes.hypergraph import hypergraph from random import randint, choice, shuffle #@UnusedImport from time import time # Generator def generate(num_nodes, num_edges, directed=False, weight_range=(1, 1)): """ Create a random graph. @type num_nodes: number @param num_nodes: Number of nodes. @type num_edges: number @param num_edges: Number of edges. @type directed: bool @param directed: Whether the generated graph should be directed or not. @type weight_range: tuple @param weight_range: tuple of two integers as lower and upper limits on randomly generated weights (uniform distribution). """ # Graph creation if directed: random_graph = digraph() else: random_graph = graph() # Nodes nodes = range(num_nodes) random_graph.add_nodes(nodes) # Build a list of all possible edges edges = [] edges_append = edges.append for x in nodes: for y in nodes: if ((directed and x != y) or (x > y)): edges_append((x, y)) # Randomize the list shuffle(edges) # Add edges to the graph min_wt = min(weight_range) max_wt = max(weight_range) for i in range(num_edges): each = edges[i] random_graph.add_edge((each[0], each[1]), wt = randint(min_wt, max_wt)) return random_graph def generate_hypergraph(num_nodes, num_edges, r = 0): """ Create a random hyper graph. @type num_nodes: number @param num_nodes: Number of nodes. @type num_edges: number @param num_edges: Number of edges. @type r: number @param r: Uniform edges of size r. """ # Graph creation random_graph = hypergraph() # Nodes nodes = list(map(str, list(range(num_nodes)))) random_graph.add_nodes(nodes) # Base edges edges = list(map(str, list(range(num_nodes, num_nodes+num_edges)))) random_graph.add_hyperedges(edges) # Connect the edges if 0 == r: # Add each edge with 50/50 probability for e in edges: for n in nodes: if choice([True, False]): random_graph.link(n, e) else: # Add only uniform edges for e in edges: # First shuffle the nodes shuffle(nodes) # Then take the first r nodes for i in range(r): random_graph.link(nodes[i], e) return random_graph python-graph-1.8.2/core/pygraph/algorithms/filters/0000755000175000017500000000000012012025435021413 5ustar morphmorphpython-graph-1.8.2/core/pygraph/algorithms/filters/radius.py0000644000175000017500000000564011276032451023270 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Radial search filter. """ class radius(object): """ Radial search filter. This will keep searching contained inside a specified limit. """ def __init__(self, radius): """ Initialize the filter. @type radius: number @param radius: Search radius. """ self.graph = None self.spanning_tree = None self.radius = radius self.done = False def configure(self, graph, spanning_tree): """ Configure the filter. @type graph: graph @param graph: Graph. @type spanning_tree: dictionary @param spanning_tree: Spanning tree. """ self.graph = graph self.spanning_tree = spanning_tree def __call__(self, node, parent): """ Decide if the given node should be included in the search process. @type node: node @param node: Given node. @type parent: node @param parent: Given node's parent in the spanning tree. @rtype: boolean @return: Whether the given node should be included in the search process. """ def cost_to_root(node): if (node is not None): return cost_to_parent(node, st[node]) + cost_to_root(st[node]) else: return 0 def cost_to_parent(node, parent): if (parent is not None): return gr.edge_weight((parent, node)) else: return 0 gr = self.graph st = self.spanning_tree cost = cost_to_parent(node, parent) + cost_to_root(parent) if (cost <= self.radius): return True else: return Falsepython-graph-1.8.2/core/pygraph/algorithms/filters/null.py0000644000175000017500000000415011242070440022737 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Null searching filter. """ class null(object): """ Null search filter. """ def __init__(self): """ Initialize the filter. """ self.graph = None self.spanning_tree = None def configure(self, graph, spanning_tree): """ Configure the filter. @type graph: graph @param graph: Graph. @type spanning_tree: dictionary @param spanning_tree: Spanning tree. """ self.graph = graph self.spanning_tree = spanning_tree def __call__(self, node, parent): """ Decide if the given node should be included in the search process. @type node: node @param node: Given node. @type parent: node @param parent: Given node's parent in the spanning tree. @rtype: boolean @return: Whether the given node should be included in the search process. """ return Truepython-graph-1.8.2/core/pygraph/algorithms/filters/find.py0000644000175000017500000000465111242070440022713 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Search filter for finding a specific node. """ class find(object): """ Search filter for finding a specific node. """ def __init__(self, target): """ Initialize the filter. @type target: node @param target: Target node. """ self.graph = None self.spanning_tree = None self.target = target self.done = False def configure(self, graph, spanning_tree): """ Configure the filter. @type graph: graph @param graph: Graph. @type spanning_tree: dictionary @param spanning_tree: Spanning tree. """ self.graph = graph self.spanning_tree = spanning_tree def __call__(self, node, parent): """ Decide if the given node should be included in the search process. @type node: node @param node: Given node. @type parent: node @param parent: Given node's parent in the spanning tree. @rtype: boolean @return: Whether the given node should be included in the search process. """ if (not self.done): if (node == self.target): self.done = True return True else: return Falsepython-graph-1.8.2/core/pygraph/algorithms/filters/__init__.py0000644000175000017500000000230111260747672023542 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Set of searching filters. """ __import__('pkg_resources').declare_namespace(__name__) python-graph-1.8.2/core/pygraph/algorithms/cycles.py0000644000175000017500000000654311720250531021611 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Cycle detection algorithms. @sort: find_cycle """ # Imports from pygraph.classes.exceptions import InvalidGraphType from pygraph.classes.digraph import digraph as digraph_class from pygraph.classes.graph import graph as graph_class from sys import getrecursionlimit, setrecursionlimit def find_cycle(graph): """ Find a cycle in the given graph. This function will return a list of nodes which form a cycle in the graph or an empty list if no cycle exists. @type graph: graph, digraph @param graph: Graph. @rtype: list @return: List of nodes. """ if (isinstance(graph, graph_class)): directed = False elif (isinstance(graph, digraph_class)): directed = True else: raise InvalidGraphType def find_cycle_to_ancestor(node, ancestor): """ Find a cycle containing both node and ancestor. """ path = [] while (node != ancestor): if (node is None): return [] path.append(node) node = spanning_tree[node] path.append(node) path.reverse() return path def dfs(node): """ Depth-first search subfunction. """ visited[node] = 1 # Explore recursively the connected component for each in graph[node]: if (cycle): return if (each not in visited): spanning_tree[each] = node dfs(each) else: if (directed or spanning_tree[node] != each): cycle.extend(find_cycle_to_ancestor(node, each)) recursionlimit = getrecursionlimit() setrecursionlimit(max(len(graph.nodes())*2,recursionlimit)) visited = {} # List for marking visited and non-visited nodes spanning_tree = {} # Spanning tree cycle = [] # Algorithm outer-loop for each in graph: # Select a non-visited node if (each not in visited): spanning_tree[each] = None # Explore node's connected component dfs(each) if (cycle): setrecursionlimit(recursionlimit) return cycle setrecursionlimit(recursionlimit) return [] python-graph-1.8.2/core/pygraph/algorithms/critical.py0000644000175000017500000001320111300062627022107 0ustar morphmorph# Copyright (c) 2009 Pedro Matiello # Tomaz Kovacic # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Critical path algorithms and transitivity detection algorithm. @sort: critical_path, transitive_edges """ # Imports from pygraph.algorithms.cycles import find_cycle from pygraph.algorithms.traversal import traversal from pygraph.algorithms.sorting import topological_sorting def _intersection(A,B): """ A simple function to find an intersection between two arrays. @type A: List @param A: First List @type B: List @param B: Second List @rtype: List @return: List of Intersections """ intersection = [] for i in A: if i in B: intersection.append(i) return intersection def transitive_edges(graph): """ Return a list of transitive edges. Example of transitivity within graphs: A -> B, B -> C, A -> C in this case the transitive edge is: A -> C @attention: This function is only meaningful for directed acyclic graphs. @type graph: digraph @param graph: Digraph @rtype: List @return: List containing tuples with transitive edges (or an empty array if the digraph contains a cycle) """ #if the graph contains a cycle we return an empty array if not len(find_cycle(graph)) == 0: return [] tranz_edges = [] # create an empty array that will contain all the tuples #run trough all the nodes in the graph for start in topological_sorting(graph): #find all the successors on the path for the current node successors = [] for a in traversal(graph,start,'pre'): successors.append(a) del successors[0] #we need all the nodes in it's path except the start node itself for next in successors: #look for an intersection between all the neighbors of the #given node and all the neighbors from the given successor intersect_array = _intersection(graph.neighbors(next), graph.neighbors(start) ) for a in intersect_array: if graph.has_edge((start, a)): ##check for the detected edge and append it to the returned array tranz_edges.append( (start,a) ) return tranz_edges # return the final array def critical_path(graph): """ Compute and return the critical path in an acyclic directed weighted graph. @attention: This function is only meaningful for directed weighted acyclic graphs @type graph: digraph @param graph: Digraph @rtype: List @return: List containing all the nodes in the path (or an empty array if the graph contains a cycle) """ #if the graph contains a cycle we return an empty array if not len(find_cycle(graph)) == 0: return [] #this empty dictionary will contain a tuple for every single node #the tuple contains the information about the most costly predecessor #of the given node and the cost of the path to this node #(predecessor, cost) node_tuples = {} topological_nodes = topological_sorting(graph) #all the tuples must be set to a default value for every node in the graph for node in topological_nodes: node_tuples.update( {node :(None, 0)} ) #run trough all the nodes in a topological order for node in topological_nodes: predecessors =[] #we must check all the predecessors for pre in graph.incidents(node): max_pre = node_tuples[pre][1] predecessors.append( (pre, graph.edge_weight( (pre, node) ) + max_pre ) ) max = 0; max_tuple = (None, 0) for i in predecessors:#look for the most costly predecessor if i[1] >= max: max = i[1] max_tuple = i #assign the maximum value to the given node in the node_tuples dictionary node_tuples[node] = max_tuple #find the critical node max = 0; critical_node = None for k,v in list(node_tuples.items()): if v[1] >= max: max= v[1] critical_node = k path = [] #find the critical path with backtracking trought the dictionary def mid_critical_path(end): if node_tuples[end][0] != None: path.append(end) mid_critical_path(node_tuples[end][0]) else: path.append(end) #call the recursive function mid_critical_path(critical_node) path.reverse() return path #return the array containing the critical pathpython-graph-1.8.2/core/pygraph/algorithms/accessibility.py0000644000175000017500000002410211406535144023154 0ustar morphmorph# Copyright (c) 2007-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Accessibility algorithms. @sort: accessibility, connected_components, cut_edges, cut_nodes, mutual_accessibility """ # Imports from sys import getrecursionlimit, setrecursionlimit # Transitive-closure def accessibility(graph): """ Accessibility matrix (transitive closure). @type graph: graph, digraph, hypergraph @param graph: Graph. @rtype: dictionary @return: Accessibility information for each node. """ recursionlimit = getrecursionlimit() setrecursionlimit(max(len(graph.nodes())*2,recursionlimit)) accessibility = {} # Accessibility matrix # For each node i, mark each node j if that exists a path from i to j. for each in graph: access = {} # Perform DFS to explore all reachable nodes _dfs(graph, access, 1, each) accessibility[each] = list(access.keys()) setrecursionlimit(recursionlimit) return accessibility # Strongly connected components def mutual_accessibility(graph): """ Mutual-accessibility matrix (strongly connected components). @type graph: graph, digraph @param graph: Graph. @rtype: dictionary @return: Mutual-accessibility information for each node. """ recursionlimit = getrecursionlimit() setrecursionlimit(max(len(graph.nodes())*2,recursionlimit)) mutual_access = {} stack = [] low = {} def visit(node): if node in low: return num = len(low) low[node] = num stack_pos = len(stack) stack.append(node) for successor in graph.neighbors(node): visit(successor) low[node] = min(low[node], low[successor]) if num == low[node]: component = stack[stack_pos:] del stack[stack_pos:] component.sort() for each in component: mutual_access[each] = component for item in component: low[item] = len(graph) for node in graph: visit(node) setrecursionlimit(recursionlimit) return mutual_access # Connected components def connected_components(graph): """ Connected components. @type graph: graph, hypergraph @param graph: Graph. @rtype: dictionary @return: Pairing that associates each node to its connected component. """ recursionlimit = getrecursionlimit() setrecursionlimit(max(len(graph.nodes())*2,recursionlimit)) visited = {} count = 1 # For 'each' node not found to belong to a connected component, find its connected # component. for each in graph: if (each not in visited): _dfs(graph, visited, count, each) count = count + 1 setrecursionlimit(recursionlimit) return visited # Limited DFS implementations used by algorithms here def _dfs(graph, visited, count, node): """ Depth-first search subfunction adapted for accessibility algorithms. @type graph: graph, digraph, hypergraph @param graph: Graph. @type visited: dictionary @param visited: List of nodes (visited nodes are marked non-zero). @type count: number @param count: Counter of connected components. @type node: node @param node: Node to be explored by DFS. """ visited[node] = count # Explore recursively the connected component for each in graph[node]: if (each not in visited): _dfs(graph, visited, count, each) # Cut-Edge and Cut-Vertex identification # This works by creating a spanning tree for the graph and keeping track of the preorder number # of each node in the graph in pre[]. The low[] number for each node tracks the pre[] number of # the node with lowest pre[] number reachable from the first node. # # An edge (u, v) will be a cut-edge low[u] == pre[v]. Suppose v under the spanning subtree with # root u. This means that, from u, through a path inside this subtree, followed by an backarc, # one can not get out the subtree. So, (u, v) is the only connection between this subtree and # the remaining parts of the graph and, when removed, will increase the number of connected # components. # Similarly, a node u will be a cut node if any of the nodes v in the spanning subtree rooted in # u are so that low[v] > pre[u], which means that there's no path from v to outside this subtree # without passing through u. def cut_edges(graph): """ Return the cut-edges of the given graph. A cut edge, or bridge, is an edge of a graph whose removal increases the number of connected components in the graph. @type graph: graph, hypergraph @param graph: Graph. @rtype: list @return: List of cut-edges. """ recursionlimit = getrecursionlimit() setrecursionlimit(max(len(graph.nodes())*2,recursionlimit)) # Dispatch if we have a hypergraph if 'hypergraph' == graph.__class__.__name__: return _cut_hyperedges(graph) pre = {} # Pre-ordering low = {} # Lowest pre[] reachable from this node going down the spanning tree + one backedge spanning_tree = {} reply = [] pre[None] = 0 for each in graph: if (each not in pre): spanning_tree[each] = None _cut_dfs(graph, spanning_tree, pre, low, reply, each) setrecursionlimit(recursionlimit) return reply def _cut_hyperedges(hypergraph): """ Return the cut-hyperedges of the given hypergraph. @type hypergraph: hypergraph @param hypergraph: Hypergraph @rtype: list @return: List of cut-nodes. """ edges_ = cut_nodes(hypergraph.graph) edges = [] for each in edges_: if (each[1] == 'h'): edges.append(each[0]) return edges def cut_nodes(graph): """ Return the cut-nodes of the given graph. A cut node, or articulation point, is a node of a graph whose removal increases the number of connected components in the graph. @type graph: graph, hypergraph @param graph: Graph. @rtype: list @return: List of cut-nodes. """ recursionlimit = getrecursionlimit() setrecursionlimit(max(len(graph.nodes())*2,recursionlimit)) # Dispatch if we have a hypergraph if 'hypergraph' == graph.__class__.__name__: return _cut_hypernodes(graph) pre = {} # Pre-ordering low = {} # Lowest pre[] reachable from this node going down the spanning tree + one backedge reply = {} spanning_tree = {} pre[None] = 0 # Create spanning trees, calculate pre[], low[] for each in graph: if (each not in pre): spanning_tree[each] = None _cut_dfs(graph, spanning_tree, pre, low, [], each) # Find cuts for each in graph: # If node is not a root if (spanning_tree[each] is not None): for other in graph[each]: # If there is no back-edge from descendent to a ancestral of each if (low[other] >= pre[each] and spanning_tree[other] == each): reply[each] = 1 # If node is a root else: children = 0 for other in graph: if (spanning_tree[other] == each): children = children + 1 # root is cut-vertex iff it has two or more children if (children >= 2): reply[each] = 1 setrecursionlimit(recursionlimit) return list(reply.keys()) def _cut_hypernodes(hypergraph): """ Return the cut-nodes of the given hypergraph. @type hypergraph: hypergraph @param hypergraph: Hypergraph @rtype: list @return: List of cut-nodes. """ nodes_ = cut_nodes(hypergraph.graph) nodes = [] for each in nodes_: if (each[1] == 'n'): nodes.append(each[0]) return nodes def _cut_dfs(graph, spanning_tree, pre, low, reply, node): """ Depth first search adapted for identification of cut-edges and cut-nodes. @type graph: graph, digraph @param graph: Graph @type spanning_tree: dictionary @param spanning_tree: Spanning tree being built for the graph by DFS. @type pre: dictionary @param pre: Graph's preordering. @type low: dictionary @param low: Associates to each node, the preordering index of the node of lowest preordering accessible from the given node. @type reply: list @param reply: List of cut-edges. @type node: node @param node: Node to be explored by DFS. """ pre[node] = pre[None] low[node] = pre[None] pre[None] = pre[None] + 1 for each in graph[node]: if (each not in pre): spanning_tree[each] = node _cut_dfs(graph, spanning_tree, pre, low, reply, each) if (low[node] > low[each]): low[node] = low[each] if (low[each] == pre[each]): reply.append((node, each)) elif (low[node] > pre[each] and spanning_tree[node] != each): low[node] = pre[each] python-graph-1.8.2/core/pygraph/algorithms/__init__.py0000644000175000017500000000241311242074006022056 0ustar morphmorph# Copyright (c) 2008-2009 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ Algorithms This subpackage contains a set of modules, each one of them containing some algorithms. """ __import__('pkg_resources').declare_namespace(__name__) python-graph-1.8.2/core/pygraph/__init__.py0000644000175000017500000000437112000360160017702 0ustar morphmorph# Copyright (c) 2007-2012 Pedro Matiello # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. """ B{python-graph} A library for working with graphs in Python. @version: 1.8.2 L{Data structure} classes are located at C{pygraph.classes}. L{Exception} classes are located at C{pygraph.classes.exceptions}. L{Search filters} are located at C{pygraph.algorithms.filters}. L{Heuristics} for the A* algorithm are exposed in C{pygraph.algorithms.heuristics}. A quick introductory example: >>> # Import the module and instantiate a graph object >>> from pygraph.classes.graph import graph >>> from pygraph.algorithms.searching import depth_first_search >>> gr = graph() >>> # Add nodes >>> gr.add_nodes(['X','Y','Z']) >>> gr.add_nodes(['A','B','C']) >>> # Add edges >>> gr.add_edge(('X','Y')) >>> gr.add_edge(('X','Z')) >>> gr.add_edge(('A','B')) >>> gr.add_edge(('A','C')) >>> gr.add_edge(('Y','B')) >>> # Depth first search rooted on node X >>> st, pre, post = depth_first_search(gr, root='X') >>> # Print the spanning tree >>> print st {'A': 'B', 'C': 'A', 'B': 'Y', 'Y': 'X', 'X': None, 'Z': 'X'} """ __import__('pkg_resources').declare_namespace(__name__) python-graph-1.8.2/core/distribute_setup.py0000644000175000017500000003673711701075071020115 0ustar morphmorph#!python """Bootstrap distribute installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from distribute_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import os import sys import time import fnmatch import tempfile import tarfile from distutils import log try: from site import USER_SITE except ImportError: USER_SITE = None try: import subprocess def _python_cmd(*args): args = (sys.executable,) + args return subprocess.call(args) == 0 except ImportError: # will be used for python 2.3 def _python_cmd(*args): args = (sys.executable,) + args # quoting arguments if windows if sys.platform == 'win32': def quote(arg): if ' ' in arg: return '"%s"' % arg return arg args = [quote(arg) for arg in args] return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 DEFAULT_VERSION = "0.6.24" DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" SETUPTOOLS_FAKED_VERSION = "0.6c11" SETUPTOOLS_PKG_INFO = """\ Metadata-Version: 1.0 Name: setuptools Version: %s Summary: xxxx Home-page: xxx Author: xxx Author-email: xxx License: xxx Description: xxx """ % SETUPTOOLS_FAKED_VERSION def _install(tarball): # extracting the tarball tmpdir = tempfile.mkdtemp() log.warn('Extracting in %s', tmpdir) old_wd = os.getcwd() try: os.chdir(tmpdir) tar = tarfile.open(tarball) _extractall(tar) tar.close() # going in the directory subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) os.chdir(subdir) log.warn('Now working in %s', subdir) # installing log.warn('Installing Distribute') if not _python_cmd('setup.py', 'install'): log.warn('Something went wrong during the installation.') log.warn('See the error message above.') finally: os.chdir(old_wd) def _build_egg(egg, tarball, to_dir): # extracting the tarball tmpdir = tempfile.mkdtemp() log.warn('Extracting in %s', tmpdir) old_wd = os.getcwd() try: os.chdir(tmpdir) tar = tarfile.open(tarball) _extractall(tar) tar.close() # going in the directory subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) os.chdir(subdir) log.warn('Now working in %s', subdir) # building an egg log.warn('Building a Distribute egg in %s', to_dir) _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) finally: os.chdir(old_wd) # returning the result log.warn(egg) if not os.path.exists(egg): raise IOError('Could not build the egg.') def _do_download(version, download_base, to_dir, download_delay): egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' % (version, sys.version_info[0], sys.version_info[1])) if not os.path.exists(egg): tarball = download_setuptools(version, download_base, to_dir, download_delay) _build_egg(egg, tarball, to_dir) sys.path.insert(0, egg) import setuptools setuptools.bootstrap_install_from = egg def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15, no_fake=True): # making sure we use the absolute path to_dir = os.path.abspath(to_dir) was_imported = 'pkg_resources' in sys.modules or \ 'setuptools' in sys.modules try: try: import pkg_resources if not hasattr(pkg_resources, '_distribute'): if not no_fake: _fake_setuptools() raise ImportError except ImportError: return _do_download(version, download_base, to_dir, download_delay) try: pkg_resources.require("distribute>="+version) return except pkg_resources.VersionConflict: e = sys.exc_info()[1] if was_imported: sys.stderr.write( "The required version of distribute (>=%s) is not available,\n" "and can't be installed while this script is running. Please\n" "install a more recent version first, using\n" "'easy_install -U distribute'." "\n\n(Currently using %r)\n" % (version, e.args[0])) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok return _do_download(version, download_base, to_dir, download_delay) except pkg_resources.DistributionNotFound: return _do_download(version, download_base, to_dir, download_delay) finally: if not no_fake: _create_fake_setuptools_pkg_info(to_dir) def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay=15): """Download distribute from a specified location and return its filename `version` should be a valid distribute version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ # making sure we use the absolute path to_dir = os.path.abspath(to_dir) try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen tgz_name = "distribute-%s.tar.gz" % version url = download_base + tgz_name saveto = os.path.join(to_dir, tgz_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: log.warn("Downloading %s", url) src = urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = src.read() dst = open(saveto, "wb") dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def _no_sandbox(function): def __no_sandbox(*args, **kw): try: from setuptools.sandbox import DirectorySandbox if not hasattr(DirectorySandbox, '_old'): def violation(*args): pass DirectorySandbox._old = DirectorySandbox._violation DirectorySandbox._violation = violation patched = True else: patched = False except ImportError: patched = False try: return function(*args, **kw) finally: if patched: DirectorySandbox._violation = DirectorySandbox._old del DirectorySandbox._old return __no_sandbox def _patch_file(path, content): """Will backup the file then patch it""" existing_content = open(path).read() if existing_content == content: # already patched log.warn('Already patched.') return False log.warn('Patching...') _rename_path(path) f = open(path, 'w') try: f.write(content) finally: f.close() return True _patch_file = _no_sandbox(_patch_file) def _same_content(path, content): return open(path).read() == content def _rename_path(path): new_name = path + '.OLD.%s' % time.time() log.warn('Renaming %s into %s', path, new_name) os.rename(path, new_name) return new_name def _remove_flat_installation(placeholder): if not os.path.isdir(placeholder): log.warn('Unkown installation at %s', placeholder) return False found = False for file in os.listdir(placeholder): if fnmatch.fnmatch(file, 'setuptools*.egg-info'): found = True break if not found: log.warn('Could not locate setuptools*.egg-info') return log.warn('Removing elements out of the way...') pkg_info = os.path.join(placeholder, file) if os.path.isdir(pkg_info): patched = _patch_egg_dir(pkg_info) else: patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) if not patched: log.warn('%s already patched.', pkg_info) return False # now let's move the files out of the way for element in ('setuptools', 'pkg_resources.py', 'site.py'): element = os.path.join(placeholder, element) if os.path.exists(element): _rename_path(element) else: log.warn('Could not find the %s element of the ' 'Setuptools distribution', element) return True _remove_flat_installation = _no_sandbox(_remove_flat_installation) def _after_install(dist): log.warn('After install bootstrap.') placeholder = dist.get_command_obj('install').install_purelib _create_fake_setuptools_pkg_info(placeholder) def _create_fake_setuptools_pkg_info(placeholder): if not placeholder or not os.path.exists(placeholder): log.warn('Could not find the install location') return pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) setuptools_file = 'setuptools-%s-py%s.egg-info' % \ (SETUPTOOLS_FAKED_VERSION, pyver) pkg_info = os.path.join(placeholder, setuptools_file) if os.path.exists(pkg_info): log.warn('%s already exists', pkg_info) return log.warn('Creating %s', pkg_info) f = open(pkg_info, 'w') try: f.write(SETUPTOOLS_PKG_INFO) finally: f.close() pth_file = os.path.join(placeholder, 'setuptools.pth') log.warn('Creating %s', pth_file) f = open(pth_file, 'w') try: f.write(os.path.join(os.curdir, setuptools_file)) finally: f.close() _create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info) def _patch_egg_dir(path): # let's check if it's already patched pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') if os.path.exists(pkg_info): if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): log.warn('%s already patched.', pkg_info) return False _rename_path(path) os.mkdir(path) os.mkdir(os.path.join(path, 'EGG-INFO')) pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') f = open(pkg_info, 'w') try: f.write(SETUPTOOLS_PKG_INFO) finally: f.close() return True _patch_egg_dir = _no_sandbox(_patch_egg_dir) def _before_install(): log.warn('Before install bootstrap.') _fake_setuptools() def _under_prefix(location): if 'install' not in sys.argv: return True args = sys.argv[sys.argv.index('install')+1:] for index, arg in enumerate(args): for option in ('--root', '--prefix'): if arg.startswith('%s=' % option): top_dir = arg.split('root=')[-1] return location.startswith(top_dir) elif arg == option: if len(args) > index: top_dir = args[index+1] return location.startswith(top_dir) if arg == '--user' and USER_SITE is not None: return location.startswith(USER_SITE) return True def _fake_setuptools(): log.warn('Scanning installed packages') try: import pkg_resources except ImportError: # we're cool log.warn('Setuptools or Distribute does not seem to be installed.') return ws = pkg_resources.working_set try: setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', replacement=False)) except TypeError: # old distribute API setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) if setuptools_dist is None: log.warn('No setuptools distribution found') return # detecting if it was already faked setuptools_location = setuptools_dist.location log.warn('Setuptools installation detected at %s', setuptools_location) # if --root or --preix was provided, and if # setuptools is not located in them, we don't patch it if not _under_prefix(setuptools_location): log.warn('Not patching, --root or --prefix is installing Distribute' ' in another location') return # let's see if its an egg if not setuptools_location.endswith('.egg'): log.warn('Non-egg installation') res = _remove_flat_installation(setuptools_location) if not res: return else: log.warn('Egg installation') pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') if (os.path.exists(pkg_info) and _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): log.warn('Already patched.') return log.warn('Patching...') # let's create a fake egg replacing setuptools one res = _patch_egg_dir(setuptools_location) if not res: return log.warn('Patched done.') _relaunch() def _relaunch(): log.warn('Relaunching...') # we have to relaunch the process # pip marker to avoid a relaunch bug if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']: sys.argv[0] = 'setup.py' args = [sys.executable] + sys.argv sys.exit(subprocess.call(args)) def _extractall(self, path=".", members=None): """Extract all members from the archive to the current working directory and set owner, modification time and permissions on directories afterwards. `path' specifies a different directory to extract to. `members' is optional and must be a subset of the list returned by getmembers(). """ import copy import operator from tarfile import ExtractError directories = [] if members is None: members = self for tarinfo in members: if tarinfo.isdir(): # Extract directories with a safe mode. directories.append(tarinfo) tarinfo = copy.copy(tarinfo) tarinfo.mode = 448 # decimal for oct 0700 self.extract(tarinfo, path) # Reverse sort directories. if sys.version_info < (2, 4): def sorter(dir1, dir2): return cmp(dir1.name, dir2.name) directories.sort(sorter) directories.reverse() else: directories.sort(key=operator.attrgetter('name'), reverse=True) # Set correct owner, mtime and filemode on directories. for tarinfo in directories: dirpath = os.path.join(path, tarinfo.name) try: self.chown(tarinfo, dirpath) self.utime(tarinfo, dirpath) self.chmod(tarinfo, dirpath) except ExtractError: e = sys.exc_info()[1] if self.errorlevel > 1: raise else: self._dbg(1, "tarfile: %s" % e) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" tarball = download_setuptools() _install(tarball) if __name__ == '__main__': import os os.environ.set("HTTP_HOST",r"http//ldnproxy.ldn.emea.cib:9090") main(sys.argv[1:]) python-graph-1.8.2/COPYING0000644000175000017500000000323012000360160014213 0ustar morphmorphCopyright (c) 2007-2012 Pedro Matiello Christian Muise Eugen Zagorodniy Johannes Reinhardt Nathan Davis Paul Harrison Rhys Ulerich Roy Smith Salim Fadhley Tomaz Kovacic Zsolt Haraszti Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. python-graph-1.8.2/Changelog0000644000175000017500000001767512000363030015013 0ustar morphmorphpython-graph A library for working with graphs in Python -------------------------------------------------------------------------------- CHANGELOG Release 1.8.2 [July 14, 2012] Fixes: The find_cycle function now accepts instances of any subtype of graph and digraph. Release 1.8.1 [Jan 08, 2012] Enhancements: Shortest-path now executes in O(n*log(n)) instead of O(n^2). Fixes: Shortest-path raises KeyError when the source node is not on the graph; Bellman-Ford algorithm now works for unconnected graphs (Issue 87); Linking, unlinking and relinking a hypernode to hyperedge now works as expected (Issue 86); Graph comparison does not raise exceptions anymore (Issue 88); Fixed undesired sharing of attribute lists (Issue 92); Fixed reading of XML-stored graphs with edge attributes; Fixed calculation of minimal spanning trees of graphs with negative-weighted edges (Issue 102). Release 1.8.0 [Oct 01, 2010] Enhancements: Added Pagerank algorithm; Added Gomory-Hu cut-tree algorithm. Fixes: Edges from one node to itself are no longer duplicated (Issue 75). Release 1.7.0 [Mar 20, 2010] Enhancements: Added equality test for graphs, digraphs and hypergraphs; Added has_edge() and has_hyperedge() methods to hypergraph objects; Accepting subtypes of graph, digraph and hypergraph in dot-language output (Issue 64); Added Bellman-Ford algorithm; Added Edmonds-Karp Maximum-Flow algorithm. Fixes: Adding an edge with a label to a digraph now works again; Deleting an edge of a hypergraph now deletes its attributes; Node attributes on hypergraphs work now; Checking for node equality correctly in find_cycle; Avoiding errors caused by deep recursion on many algorithms (Issue 66). Release 1.6.3 [Dec 13, 2009] Enhancements: Added Python3 support (support for Python 2.5 and lower was dropped). Fixes: Adding a graph to a digraph now works (Issue 39); Fixed the reading of graphs and digraphs stored in XML. Important API Changes: Edges are now passed around as generic objects. In the case of graph / digraph this is a tuple; Removed traversal() method from graph and digraph classes; Removed accessibility, connected_components, cut_nodes and cut_hyperedges from hypergraph class; Functions for reading a hypergraph doesn't take an empty hypergraph as argument anymore. Release 1.6.2 [Sep 30, 2009] Important API Changes: Adding an arrow to an non existing node on a digraph now fails sanely (Issue 35); Adding an already added node to a graph or digraph now raises an exception (AdditionError); Adding an already added edge to a graph or digraph now raises an exception (AdditionError); pygraph.classes.Classname.classname classes were renamed to pygraph.classes.classname.classname; pygraph.algorithms.filters.Filtername.filtername filters were renamed to pygraph.algorithms.filters.filtername.filtername; pygraph.algorithms.heuristics.Heuristicname.heuristicname heuristics were renamed to pygraph.algorithms.heuristics.heuristicname.heuristicname; hypergraph's read() and write() methods were removed. Release 1.6.1 [Jul 04, 2009] Enhancements: Added reverse method to the digraph class. Important API Changes: Removed methods calling algorithms from graph and digraph classes; pygraph.algorithms.cycles.find_cycle does not take argument directed anymore; Removed methods read, write and generate from graph and digraph classes; Functions for writing and reading graphs now in pygraph.readwrite. Release 1.6.0 [Jun 06, 2009] Important API Changes: Module name was renamed to pygraph; python_graph_exception was renamed to GraphError; Exception unreachable was renamed to NodeUnreachable; get_edge_weight was renamed to edge_weight; get_edge_label was renamed to edge_label; get_edge_attributes was renamed to edge_attributes; get_node_attributes was renamed to node_attributes; degree was renamed to node_degree; order was renamed to node_order. Release 1.5.0 [May 03, 2009] Enhancements: Assymptotically faster Mutual Accessibility (now using Tarjan's algorithm); DOT-Language importing; Transitive edge detection; Critical path algorithm. Fixes: Cycle detection algorithm was reporting wrong results on some digraphs; Removed Minimal Spanning Tree from Digraphs as Prim's algorithm does not work on them (Issue 28). Deletion of A--A edge raised an exception; Deletion of an node with an A--A edge raised an exception. Important API Changes: Removed minimal_spanning_tree() method from the digraph class. Release 1.4.2 [Feb 22, 2009] Fixes: find_cycle() trapped itself in infinite recursion in some digraphs (Issue 22). Release 1.4.1 [Feb 09, 2009] Fixes: graph.algorithms.filters was not being installed (Issue 20). Release 1.4.0 [Feb 07, 2009] Enhancements: Added Asearch algorithm (as heuristic_search); Added Chow's and Euclidean heuristics for A*; Added filtered depth-first and breadth-first search; Added 'find' search filter (stops the search after reaching a target node); Added 'radius' search filter (radial limit for searching); Moved to setuptools. Fixes: Breadth first search was omitting the first node in level ordering when no root was specified. Release 1.3.1 [Oct 27, 2008] Fixes: Graph and digraph inverse was not working; Node removal in digraphs was not deleting all relevant edges (Issue 13). Important API Changes: Deprecated methods were removed. Release 1.3.0 [Sep 28, 2008] Enhancements: Tree traversals (preorder and postorder). Fixes: Node insertion is much faster now (Issue 11). Hypernode/hyperedge insertion also much faster. Important API Changes: get_nodes() is now nodes(); get_edges() is now edges(); get_neighbors() is now neighbors(); get_incidents() is now incidents(); get_order() is now order(); get_degree() is now degree(). (Former method names are deprecated and will be removed in the next release.) Release 1.2.0 [Sep 09, 2008] Enhancements: Moved to new class style; Graphs and digraphs are separated classes now; Added level-based ordering to breadth first search; Graph object is now iterable; Graph object is now a container and graphobj[nodeid] iterates too; Support for node and edge attributes (Issue 5); Node deletion. Fixes: Install now works with a prefix (Issue 10); Shortest path spanning trees did not had an explicit root. Important API Changes: breadth_first_search() now returns a tuple; Arrow methods are gone. Use class digraph + edge methods for directed graphs now. Release 1.1.1 [Sep 04, 2008] Enhancements: Improved install script. Fixes: DOT Language output now works for nodes/edges labelled with spaces. Important API Changes: get_neighbours() is now get_neighbors() (Issue 9). Release 1.1.0 [Aug 31, 2008] Enhancements: Hypergraph support (Issue 4); Complete and complement graph generation; Weights in random generated graphs (Issue 8). Fixes: Fixed bug in cut-node identification; Fixed bug causing wrong results for graphs with nodes labelled with values that evaluate to False (Issue 7). Important API Changes: get_edges() now return all edges in the graph; get_neighbours() has the former behaviour of get_edges(). Release 1.0.0 [Aug 01, 2008] Adds some operations; Random graph generation; Cut-vertex/cut-edge identification. Release 0.85 [Jul 27, 2008] Adds DOT-Language output (Issue 1); Install script included (Issue 3). Release 0.75 [Jul 06, 2008] Added XML import/export; Docs are bundled now. Release 0.65 [Jun 25, 2008] DFS, BFS and MST can be generated for given roots; Added Dijkstra's shortest path algorithm (Issue 2). Release 0.50 [May 13, 2008] Some API changes; Nodes can now be arbitrary names/objects. Release 0.45 [May 12, 2008] Adds Prim's minimal spanning tree. Release 0.40 [Mar 09, 2008] Adds topological sorting; Support for weighted graphs. Release 0.30 [Aug 30, 2007] Adds algorithms for accessibility and mutual accessibility. Release 0.20 [Jul 16, 2007] Adds breadth-first search; API documentation. Release 0.10 [Jul 10, 2007] First release; Feat. basic operations and depth-first searching. python-graph-1.8.2/.DS_Store0000644000175000017500000001400412016145612014656 0ustar morphmorphBud1bwspblob―docsbwspblob―bplist00Φ  \WindowBounds[ShowSidebar]ShowStatusBar[ShowPathbar[ShowToolbar\SidebarWidth_{{334, 121}, {770, 438}}  ‡".