Skip to content

root-11/graph-theory

Repository files navigation

graph-theory

Build statuscodecovDownloadsDownloadsPyPI version

A simple graph library...
... A bit like networkx, just without the overhead...
... similar to graph-tool, without the Python 2.7 legacy...
... with code that you can explain to your boss...

Detailed tutorial evolving in the examples section.


Install:

pip install graph-theory

Upgrade:

pip install graph-theory --upgrade --no-cache

Testing:

pytest tests

Import:

import Graph
g = Graph()  

import Graph3d
g3d = Graph3D()

Modules:

moduledescription
from graph import Graph, Graph3DElementary methods (see basic methods below) for Graph and Graph3D.
from graph import ...All methods available on Graph (see table below)
from graph.assignment_problem import ...solvers for assignment problem, the Weapons-Target Assignment Problem, ...
from graph.hash import ...graph hash functions: graph hash, merkle tree, flow graph hash
from graph.random import ...graph generators for random, 2D and 3D graphs.
from graph.transshipment_problem import ...solvers for the transshipment problem
from graph.traffic_scheduling_problem import ...solvers for the traffic jams (and slide puzzle)
from graph.visuals import ...methods for creating matplotlib plots
from graph.finite_state_machine import ...finite state machine

All module functions are available from Graph and Graph3D (where applicable).

GraphGraph3Dmethodsreturnsexample
++a in gassert if g contains node a
++g.add_node(n, [obj])adds a node (with a pointer to object obj if given)
++g.copy()returns a shallow copy of g
++g.node(node1)returns object attached to node 1
++g.del_node(node1)deletes node1 and all it's edges
++g.nodes()returns a list of nodes
++len(g.nodes())returns the number of nodes
++g.nodes(from_node=1)returns nodes with edges from node 1
++g.nodes(to_node=2)returns nodes with edges to node 2
++g.nodes(in_degree=2)returns nodes with 2 incoming edges
++g.nodes(out_degree=2)returns nodes with 2 outgoing edges
++g.add_edge(1,2,3)adds edge to g for vector (1,2) with value 3
++g.edge(1,2)returns value of edge between nodes 1 and 2
++g.edge(1,2,default=3)returns default=3 if edge(1,2) doesn't exist.
similar to d.get(key, 3)
++g.del_edge(1,2)removes edge between nodes 1 and 2
++g.edges()returns a list of edges
++len(g.edges())returns the number of edges
++g.edges(path=[path])returns a list of edges (along a path if given).
++same_path(p1,p2)compares two paths to determine if they contain same sequences
ex.: [1,2,3] == [2,3,1]
++g.edges(from_node=1)returns edges outgoing from node 1
++g.edges(to_node=2)returns edges incoming to node 2
++g.from_dict(d)updates the graph from a dictionary
++g.to_dict()returns the graph as a dictionary
++g.from_list(L)updates the graph from a list
++g.to_list()return the graph as a list of edges
++g.shortest_path(start,end [, memoize, avoids])returns the distance and path for path with smallest edge sum
If memoize=True, sub results are cached for faster access if repeated calls.
If avoids=set(), then these nodes are not a part of the path.
++g.shortest_path_bidirectional(start,end)returns distance and path for the path with smallest edge sum using bidrectional search.
++g.is_connected(start,end)determines if there is a path from start to end
++g.breadth_first_search(start,end)returns the number of edges and path with fewest edges
++g.breadth_first_walk(start,end)returns a generator for a BFS walk
++g.degree_of_separation(n1,n2)returns the distance between two nodes using BFS
++g.distance_map(starts,ends, reverse)returns a dictionary with the distance from any start to any end (or reverse)
++g.network_size(n1, degree_of_separation)returns the nodes within the range given by degree_of_separation
++g.topological_sort(key)returns a generator that yields node in order from a non-cyclic graph.
++g.critical_path()returns the distance of the critical path and a list of Tasks.Example
++g.critical_path_minimize_for_slack()returns graph with artificial dependencies that minimises slack.Example
++g.phase_lines()returns a dictionary with the phase_lines for a non-cyclic graph.
++g.sources(n)returns the source_tree of node n
++g.depth_first_search(start,end)returns path using DFS and backtracking
++g.depth_scan(start, criteria)returns set of nodes where criteria is True
++g.distance_from_path(path)returns the distance for path.
++g.maximum_flow(source,sink)finds the maximum flow between a source and a sink
++g.maximum_flow_min_cut(source,sink)finds the maximum flow minimum cut between a source and a sink
++g.minimum_cost_flow(inventory, capacity)finds the total cost and flows of the capacitated minimum cost flow.
++g.solve_tsp()solves the traveling salesman problem for the graph.
Available methods: 'greedy' (default) and 'bnb
++g.subgraph_from_nodes(nodes)returns the subgraph of g involving nodes
++g.is_subgraph(g2)determines if graph g2 is a subgraph in g
++g.is_partite(n)determines if graph is n-partite
++g.has_cycles()determines if there are any cycles in the graph
++g.components()returns set of nodes in each component in g
++g.same_path(p1,p2)compares two paths, returns True if they're the same
++g.adjacency_matrix()returns the adjacency matrix for the graph
++g.all_pairs_shortest_paths()finds the shortest path between all nodes
++g.minsum()finds the node(s) with shortest total distance to all other nodes
++g.minmax()finds the node(s) with shortest maximum distance to all other nodes
++g.shortest_tree_all_pairs()finds the shortest tree for all pairs
++g.has_path(p)asserts whether a path p exists in g
++g.all_simple_paths(start,end)finds all simple paths between 2 nodes
++g.all_paths(start,end)finds all combinations of paths between 2 nodes
-+g3d.distance(n1,n2)returns the spatial distance between n1 and n2
-+g3d.n_nearest_neigur(n1, [n])returns the n nearest neigurs to node n1
-+g3d.plot()returns matplotlib plot of the graph.

FAQ

want to...doesn't work...do instead......but why?
have multiple edges between two nodesGraph(from_list=[(1,2,3), (1,2,4)]Add dummy nodes
[(1,a,3), (a,2,0),
(1,b,4),(b,2,0)]
Explicit is better than implicit.
multiple values on an edgeg.add_edge(1,2,{'a':3, 'b':4})Have two graphs
g_a.add_edge(1,2,3)
g_b.add_edge(1,2,4)
Most graph algorithms don't work with multiple values
do repeated calls to shortest pathg.shortest_path(a,b) is slowUse g.shortest_path(a,b,memoize=True) insteadmemoize uses bidirectional search and caches sub-results along the shortest path for future retrievals

Credits:

  • Arturo Soucase for packaging and testing.
  • Peter Norvig for inspiration on TSP from pytudes.
  • Harry Darby for the mountain river map.
  • Kyle Downey for depth_scan algorithm.
  • Ross Blandford for munich firebrigade centre -, traffic jam - and slide puzzle - test cases.
  • Avi Kelman for type-tolerant search, and a number of micro optimizations.
  • Joshua Crestone for all simple paths test.
  • CodeMartyLikeYou for detecting a bug in @memoize
  • Tom Carroll for detecting the bug in del_edge and inspiration for topological sort.
  • Sappique for discovering bugs in __eq__, copy and has_cycles.
  • joshinils for discovering bug where graph.edges(from_node=0) was interpreted as False.