1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

r""" 

============================================================== 

Compressed Sparse Graph Routines (:mod:`scipy.sparse.csgraph`) 

============================================================== 

 

.. currentmodule:: scipy.sparse.csgraph 

 

Fast graph algorithms based on sparse matrix representations. 

 

Contents 

======== 

 

.. autosummary:: 

:toctree: generated/ 

 

connected_components -- determine connected components of a graph 

laplacian -- compute the laplacian of a graph 

shortest_path -- compute the shortest path between points on a positive graph 

dijkstra -- use Dijkstra's algorithm for shortest path 

floyd_warshall -- use the Floyd-Warshall algorithm for shortest path 

bellman_ford -- use the Bellman-Ford algorithm for shortest path 

johnson -- use Johnson's algorithm for shortest path 

breadth_first_order -- compute a breadth-first order of nodes 

depth_first_order -- compute a depth-first order of nodes 

breadth_first_tree -- construct the breadth-first tree from a given node 

depth_first_tree -- construct a depth-first tree from a given node 

minimum_spanning_tree -- construct the minimum spanning tree of a graph 

reverse_cuthill_mckee -- compute permutation for reverse Cuthill-McKee ordering 

maximum_bipartite_matching -- compute permutation to make diagonal zero free 

structural_rank -- compute the structural rank of a graph 

NegativeCycleError 

 

.. autosummary:: 

:toctree: generated/ 

 

construct_dist_matrix 

csgraph_from_dense 

csgraph_from_masked 

csgraph_masked_from_dense 

csgraph_to_dense 

csgraph_to_masked 

reconstruct_path 

 

Graph Representations 

===================== 

This module uses graphs which are stored in a matrix format. A 

graph with N nodes can be represented by an (N x N) adjacency matrix G. 

If there is a connection from node i to node j, then G[i, j] = w, where 

w is the weight of the connection. For nodes i and j which are 

not connected, the value depends on the representation: 

 

- for dense array representations, non-edges are represented by 

G[i, j] = 0, infinity, or NaN. 

 

- for dense masked representations (of type np.ma.MaskedArray), non-edges 

are represented by masked values. This can be useful when graphs with 

zero-weight edges are desired. 

 

- for sparse array representations, non-edges are represented by 

non-entries in the matrix. This sort of sparse representation also 

allows for edges with zero weights. 

 

As a concrete example, imagine that you would like to represent the following 

undirected graph:: 

 

G 

 

(0) 

/ \ 

1 2 

/ \ 

(2) (1) 

 

This graph has three nodes, where node 0 and 1 are connected by an edge of 

weight 2, and nodes 0 and 2 are connected by an edge of weight 1. 

We can construct the dense, masked, and sparse representations as follows, 

keeping in mind that an undirected graph is represented by a symmetric matrix:: 

 

>>> G_dense = np.array([[0, 2, 1], 

... [2, 0, 0], 

... [1, 0, 0]]) 

>>> G_masked = np.ma.masked_values(G_dense, 0) 

>>> from scipy.sparse import csr_matrix 

>>> G_sparse = csr_matrix(G_dense) 

 

This becomes more difficult when zero edges are significant. For example, 

consider the situation when we slightly modify the above graph:: 

 

G2 

 

(0) 

/ \ 

0 2 

/ \ 

(2) (1) 

 

This is identical to the previous graph, except nodes 0 and 2 are connected 

by an edge of zero weight. In this case, the dense representation above 

leads to ambiguities: how can non-edges be represented if zero is a meaningful 

value? In this case, either a masked or sparse representation must be used 

to eliminate the ambiguity:: 

 

>>> G2_data = np.array([[np.inf, 2, 0 ], 

... [2, np.inf, np.inf], 

... [0, np.inf, np.inf]]) 

>>> G2_masked = np.ma.masked_invalid(G2_data) 

>>> from scipy.sparse.csgraph import csgraph_from_dense 

>>> # G2_sparse = csr_matrix(G2_data) would give the wrong result 

>>> G2_sparse = csgraph_from_dense(G2_data, null_value=np.inf) 

>>> G2_sparse.data 

array([ 2., 0., 2., 0.]) 

 

Here we have used a utility routine from the csgraph submodule in order to 

convert the dense representation to a sparse representation which can be 

understood by the algorithms in submodule. By viewing the data array, we 

can see that the zero values are explicitly encoded in the graph. 

 

Directed vs. Undirected 

----------------------- 

Matrices may represent either directed or undirected graphs. This is 

specified throughout the csgraph module by a boolean keyword. Graphs are 

assumed to be directed by default. In a directed graph, traversal from node 

i to node j can be accomplished over the edge G[i, j], but not the edge 

G[j, i]. In a non-directed graph, traversal from node i to node j can be 

accomplished over either G[i, j] or G[j, i]. If both edges are not null, 

and the two have unequal weights, then the smaller of the two is used. 

Note that a symmetric matrix will represent an undirected graph, regardless 

of whether the 'directed' keyword is set to True or False. In this case, 

using ``directed=True`` generally leads to more efficient computation. 

 

The routines in this module accept as input either scipy.sparse representations 

(csr, csc, or lil format), masked representations, or dense representations 

with non-edges indicated by zeros, infinities, and NaN entries. 

""" 

 

from __future__ import division, print_function, absolute_import 

 

__docformat__ = "restructuredtext en" 

 

__all__ = ['connected_components', 

'laplacian', 

'shortest_path', 

'floyd_warshall', 

'dijkstra', 

'bellman_ford', 

'johnson', 

'breadth_first_order', 

'depth_first_order', 

'breadth_first_tree', 

'depth_first_tree', 

'minimum_spanning_tree', 

'reverse_cuthill_mckee', 

'maximum_bipartite_matching', 

'structural_rank', 

'construct_dist_matrix', 

'reconstruct_path', 

'csgraph_masked_from_dense', 

'csgraph_from_dense', 

'csgraph_from_masked', 

'csgraph_to_dense', 

'csgraph_to_masked', 

'NegativeCycleError'] 

 

from ._laplacian import laplacian 

from ._shortest_path import shortest_path, floyd_warshall, dijkstra,\ 

bellman_ford, johnson, NegativeCycleError 

from ._traversal import breadth_first_order, depth_first_order, \ 

breadth_first_tree, depth_first_tree, connected_components 

from ._min_spanning_tree import minimum_spanning_tree 

from ._reordering import reverse_cuthill_mckee, maximum_bipartite_matching, \ 

structural_rank 

from ._tools import construct_dist_matrix, reconstruct_path,\ 

csgraph_from_dense, csgraph_to_dense, csgraph_masked_from_dense,\ 

csgraph_from_masked, csgraph_to_masked 

 

from scipy._lib._testutils import PytestTester 

test = PytestTester(__name__) 

del PytestTester