File: Tutorial.txt

package info (click to toggle)
python-networkx 0.32-2
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 2,332 kB
  • ctags: 1,020
  • sloc: python: 21,197; makefile: 67; sh: 11
file content (746 lines) | stat: -rw-r--r-- 23,158 bytes parent folder | download
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
..  -*- coding: utf-8 -*-

~~~~~~~~~~~~~~~~~
NetworkX Tutorial
~~~~~~~~~~~~~~~~~

*last updated: $Date: 2006-08-05 17:40:46 -0600 (Sat, 05 Aug 2006) $*

Introduction
============

NetworkX = Network "X"  = NX (for short)

Original Creators::

	 Aric Hagberg, hagberg@lanl.gov
	 Pieter Swart, swart@lanl.gov

NetworkX is a Python-based package for the creation, manipulation, and
study of the structure, dynamics, and function of complex networks. The
name means **Network "X"** and we pronounce it **NX**. We will refer to
(and import) NetworkX as NX for the sake of brevity.

The structure of a graph or network is encoded in the **edges**
(connections, links, ties, arcs, bonds) between **nodes** (vertices,
sites, actors). If unqualified, by graph we mean a simple undirected
graph, i.e. no self-loops and no multiple edges are allowed. By a
network we usually mean a graph with weights (fields, properties) on
nodes and/or edges.

The potential audience for NetworkX include: mathematicians,
physicists, biologists, computer scientists, social scientists. The
current state of the art of the (young and rapidly growing) science of
complex networks is presented in Albert and Barabási [BA02]_, Newman
[Newman03]_, and Dorogovtsev and Mendes [DM03]_. See also the classic
texts [Bollobas01]_, [Diestel97]_ and [West01_] for graph theoretic
results and terminology. For basic graph algorithms, we recommend the
texts of Sedgewick, e.g. [Sedgewick01]_ and [Sedgewick02]_ and the
modern survey of Brandes and Erlebach [BE05]_.
  
Why Python? Past experience showed this approach to maximize
productivity, power, multi-disciplinary scope (our application test
beds included large communication, social, data and biological
networks), and platform independence. This philosophy does not exclude
using whatever other language is appropriate for a specific subtask,
since Python is also an excellent "glue" language [Langtangen04]_. 
Equally important, Python is free, well-supported and a joy to use. 
Among the many guides to Python, we recommend the documentation at
http://www.python.org and the text by Alex Martelli [Martelli03]_.

NetworkX is free software; you can redistribute it and/or
modify it under the terms of the **LGPL** (GNU Lesser General Public
License) as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
Please see the license for more information. 

Obtaining and Installing NetworkX
==================================

You need Python. We recommend the latest stable release available
from http://www.python.org/. 

The latest version of NetworkX can be found at http://networkx.lanl.gov/. 
NetworkX will work on multiple platforms.

On Linux platforms, download the current tarball numbered, say,
networkx-x.y.z.tar.gz, to an appropriate directory, say /home/username/networks

::

   gzip -d -c networkx-x.xx.tar.gz|tar xvf-
   cd networkxx-x.xx
   # run the following with your preferred Python version
   python setup.py build
   # change to a user id that is allowed to do installation
   python setup.py install

This will install NetworkX in your Python site-packages directory.

If you don't have permission to install software on your
system, you can install into another directory using
the --prefix or --home flags to setup.py.

For example

::  

    python setup.py install --prefix=/home/username/python
    or
    python setup.py install --home=~

If you didn't install in the standard Python site-packages directory
you will need to set your PYTHONPATH variable to the alternate location.
See http://docs.python.org/inst/search-path.html for further details.


A Quick Tour
============

Building and drawing a small graph
----------------------------------

We assume you can start an interactive Python session. At the time
of writing we require Python Release 2.3.4 or later. (Although not
required, if you want to run the unit tests you will need Python 2.4
or later.) We will assume that you are familiar with Python
terminology (see the official Python website http://www.python.org for more
information).

::

  %python
  Python 2.3.4 (#1, Jun  3 2004, 14:57\:21)
  [GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
  Type "help", "copyright", "credits" or "license" for more information.
  >>>

(If you did not install NX into the Python site directory 
it might be useful to add the directory where NX is installed to
your PYTHONPATH.)

After starting Python, import the networkx module with (the recommended way)

>>> import networkx as NX

or using the usual mode for interactive experimentation that might
clobber some names already in your namespace

>>> from networkx import *

If this import fails, it means that Python cannot find the installed
module. Check your installation and your PYTHONPATH.

To save some repetition, in all the examples below we will assume that 
NX has been imported with

>>> from networkx import *

To create a new (simple) graph, call Graph() with zero or more arguments.

>>> G=Graph()

When called with zero arguments, one obtains the empty graph without
any nodes or edges.  In NX every graph or network is a Python
"object", and in Python the functions associated with an "object" are
known as methods.

The following classes are provided:

Graph
   The basic operations common to graph-like classes.
   This class implements a "simple graph"; it ignores
   multiple edges between two nodes and does not allow edges 
   from a node to itself (self-loops).

DiGraph
   Operations common to digraphs, simple graphs with directed edges.
   (A subclass of Graph.)

XGraph
   A flexible (and experimental) graph class that allows
   data/weights/labels/objects to be associated with each edge.  While
   a simple graph by default, this class can also allow multiple edges
   and self loops.  Thus, it can be used to represent a weighted
   graph, pseudograph, or network.  This additional flexibility leads to some
   degradation in performance, though usually not significant.
   (A subclass of Graph.)

XDiGraph
   A directed version of an XGraph.  
   (A subclass of DiGraph.)

Empty graph-like objects are created with

  - G=Graph()
  - G=DiGraph()
  - G=XGraph()
  - G=XGraph(selfloops=True, multiedges=True)
  - G=XDiGraph(selfloops=True, multiedges=True)

Only the XGraph and XDiGraph classes allow for the selfloops and
multiedges options.

This package implements graphs using data structures based on an
adjacency list implemented as a node-centric dictionary of
dictionaries. The dictionary contains keys corresponding to the nodes
and the values are dictionaries of neighboring node keys with the
value None (or edge data for XGraph(), or a list of edge data for
XGraph(multiedges=True)).  This allows fast addition, deletion and
lookup of nodes and neighbors in large graphs.  The underlying
datastructure should only be visible in the modules base.py and
xbase.py. In all other modules, graph-like objects are manipulated
solely via the methods defined in base.py and xbase.py, and not by
acting directly on the datastructure. This design allows one to
replace the 'dicts-of-dicts"-based datastructure with an alternative 
datastructure without excessive effort.

The following shorthand is used throughout NetworkX documentation and code:
(we use mathematical notation n,v,w,... to indicate a node, v=vertex=node).
 
G,G1,G2,H,etc:
   Graphs

n,n1,n2,u,v,v1,v2:
   nodes (vertices)

nlist,vlist:
   a list of nodes (vertices)

nbunch, vbunch:
   a "bunch" of nodes (vertices).
   an nbunch is any iterable container
   of nodes that is not itself a node in the graph. (It can be an
   iterable or an iterator, e.g. a list, set, graph, file, etc..)

e=(n1,n2):
   an edge (a Python 2-tuple) in Graph and DiGraph, 
   also written n1-n2 (if undirected) and n1->n2 (if directed).
 
e=(n1,n2,x): 
   an edge (a Python 3-tuple) in XGraph and XDiGraph, containing the two
   nodes connected and the edge data/label/object stored associated with
   the edge. The object x, or a list of objects (if multiedges=True),
   can be obtained using G.get_edge(n1,n2). In XGraph and XDiGraph,
   G.add_edge(n1,n2) is equivalent to G.add_edge(n1,n2,None). In the
   case of multiple edges between nodes n1 and n2, one can use 
   G.delete_multiedge(n1,n2) to delete all edges between n1 and n2. 

elist:
   a list of edges (as 2- or 3-tuples)

ebunch:
   a bunch of edges (as tuples)
   an ebunch is any iterable (non-string) container
   of edge-tuples. (Similar to nbunch, also see add_edge).

Warning:
  - Alhough any hashable object can be used as a node, one should not
    change the object after it has been added as a
    node (since the hash can depend on the object contents).
  - The ordering of objects within an arbitrary nbunch/ebunch
    can be machine- or implementation-dependent.
  - Algorithms applicable to arbitrary nbunch/ebunch should treat 
    them as once-through-and-exhausted iterable containers.
  - len(nbunch) and len(ebunch) need not be defined.    



Graph methods
-------------

A Graph object G has the following primitive methods associated
with it:

(You can use dir(G) to inspect the methods associated with object G.)

1. Non-mutating Graph methods:

    - len(G)       number of nodes in G
    - G.has_node(n)       
    - n in G (equivalent to G.has_node(n))
    - G.info()
    - G.nodes()
    - G.nodes_iter()
    - G.has_edge(n1,n2)
    - G.edges(), G.edges(n), G.edges(nbunch)      
    - G.edges_iter(), G.edges_iter(n), G.edges_iter(nbunch)
    - G.neighbors(n)     
    - G[n] (equivalent to G.neighbors(n))
    - G.neighbors_iter(n) # iterator over neighbors
    - G.number_of_nodes()
    - G.number_of_edges()
    - G.node_boundary(nbunch)
    - G.node_boundary(nbunch1,nbunch2)
    - G.edge_boundary(nbunch)
    - G.edge_boundary(nbunch1,nbunch2)
    - G.degree(n), G.degree(nbunch)
    - G.degree_iter(n), G.degree_iter(nbunch)
    - G.is_directed()

    The following return a new graph:

    - G.subgraph(nbunch)
    - G.subgraph(nbunch, create_using=H)
    - G.copy()
    - G.to_directed()
    - G.to_undirected()
    
2. Mutating Graph methods:

    - G.add_node(n), G.add_nodes_from(nbunch)
    - G.delete_node(n), G.delete_nodes_from(nbunch)
    - G.add_edge(n1,n2), G.add_edge(e)
    - G.add_edges_from(ebunch)
    - G.delete_edge(n1,n2), G.delete_edge(e), 
    - G.delete_edges_from(ebunch)
    - G.add_path(nlist)
    - G.add_cycle(nlist)
    - G.clear()
    - G.subgraph(nbunch,inplace=True)


Names of classes/objects use the CapWords convention,
e.g. Graph, XDiGraph. Names of functions and methods
use the lowercase_words_separated_by_underscores convention,
e.g. petersen_graph(), G.add_node(10).

G can be inspected interactively by typing "G" (without the quotes).
This will reply something like <networkx.base.Graph object at 0x40179a0c>.
(On linux machines with CPython the hexadecimal address is the memory
location of the object.) One can use G.info() for a brief summary of
the graph properties.

Examples
========

Create an empty graph with zero nodes and zero edges.

>>> from networkx import *
>>> G=Graph()

G can be grown in several ways.
By adding one node at a time:

>>> G.add_node(1)

by adding a list of nodes:

>>> G.add_nodes_from([2,3])

or by adding any nbunch of nodes (see above definition of an nbunch):

>>> H=path_graph(10)
>>> G.add_nodes_from(H)

(H can be a graph, iterator,  string,  set, or even a file.)

Any hashable object (except None) can represent a node, e.g. a text string, an
image, an XML objext, another Graph, a customized node object, etc.

>>> G.add_node(H)

(You should not change the object if the hash depends on its contents.)

G can also be grown by adding one edge at a time:

>>> G.add_edge( (1,2) )

by adding a list of edges: 

>>> G.add_edges_from([(1,2),(1,3)])

or by adding any ebunch of edges (see above definition of an ebunch):

>>> G.add_edges_from(H.edges())

One can demolish the graph in a similar fashion; using delete_node,
delete_nodes_from, delete_edge and delete_edges_from, e.g.

>>> G.delete_node(H)

There are no complaints when adding existing nodes or edges. For example:
after removing all nodes and edges,

>>> G.clear()
>>> G.add_edges_from([(1,2),(1,3)])
>>> G.add_node(1)
>>> G.add_edge((1,2))

will add new nodes/edges as required and stay quiet if they are
already present.

>>> G.add_node("spam")



At this stage the graph G consists of 4 nodes and 2 edges, as can be seen by:

>>> number_of_nodes(G)
4
>>> number_of_edges(G)
2

we can examine them with:

>>> G.nodes()
[1, 2, 3, 'spam']
>>> G.edges()
[(1, 2), (1, 3)]


Drawing a small graph
---------------------

NetworkX does not provide sophisticated graph drawing tools. We
do provide elementary drawing tools as well as an interface to use the
open source Graphviz software package.  These reside in networkx.drawing,
and will be imported if possible. See the drawing section for details.

>>> import pylab as P

To test if the import of networkx.drawing was successful 
draw G using one of:

>>> draw(G)
>>> draw_random(G)
>>> draw_circular(G)
>>> draw_spectral(G)

when drawing to an interactive display. 
Note that you may need to issue a pylab 

>>> P.show() 

command if you are not using matplotlib in interactive mode (http://matplotlib.sourceforge.net/faq.html#SHOW).

Or use

>>> draw(G)
>>> P.savefig("path.ps")

to write to the file "path.ps" in the local directory. If graphviz
and pygraphviz or pydot are available on your system, you can also use:

>>> draw_graphviz(G)
>>> write_dot(G)
graph G {
"1";
"2";
"3";
"spam";
"1" -- "2";
"1" -- "3";
}
<BLANKLINE>

You may find it useful to interactively test code using "ipython
-pylab", thereby combining the power of ipython and matplotlib.

Functions for analyzing graph properties
----------------------------------------

The structure of G can be analyzed using various graph
theoretic functions such as:
 
>>> connected_components(G)
[[1, 2, 3], ['spam']]

>>> sorted(degree(G))
[0, 1, 1, 2]

>>> clustering(G)
[0.0, 0.0, 0.0, 0.0]

Some functions defined on the nodes, e.g. degree() and clustering(), can
be given a single node or an nbunch of nodes as argument. If a single node is
specified, then a single value is returned. If an iterable nbunch is
specified, then the function will return a list of values. With no argument, 
the function will return a list of values at all nodes of the graph.
 
>>> degree(G,1)
2
>>> G.degree(1)
2

>>> sorted(degree(G,[1,2]))
[1, 2]

>>> sorted(degree(G))
[0, 1, 1, 2]

When called with the "with_labels"=True option a dict with nodes as
keys and function values as arguments is returned.

>>> degree(G,[1,2],with_labels=True)
{1: 2, 2: 1}
>>> degree(G,with_labels=True)
{1: 2, 2: 1, 3: 1, 'spam': 0}



Graph generators and graph operations
-------------------------------------

In addition to constructing graphs node-by-node or edge-by-edge, they
can also be generated by:

1. Applying classic graph operations, such as::

    subgraph(G, nbunch)      - induce subgraph of G on nodes in nbunch
    union(G1,G2)             - graph union
    disjoint_union(G1,G2)    - graph union assuming all nodes are different
    cartesian_product(G1,G2) - return Cartesian product graph
    compose(G1,G2)           - combine graphs identifying nodes common
                               to both
    complement(G)            - graph complement 
    create_empty_copy(G)     - return an empty copy of the same graph class
    convert_to_undirected(G) - return an undirected representation of G
    convert_to_directed(G)   - return a directed representation of G


2. Using a call to one of the classic small graphs, e.g.

>>> petersen=petersen_graph()
>>> tutte=tutte_graph()
>>> maze=sedgewick_maze_graph()
>>> tet=tetrahedral_graph()

3. Using a (constructive) generator for a classic graph, e.g.

>>> K_5=complete_graph(5)
>>> K_3_5=complete_bipartite_graph(3,5)
>>> barbell=barbell_graph(10,10)
>>> lollipop=lollipop_graph(10,20)
 
4. Using a stochastic graph generator, e.g.

>>> er=erdos_renyi_graph(100,0.15)
>>> ws=watts_strogatz_graph(30,3,0.1)
>>> ba=barabasi_albert_graph(100,5)
>>> red=random_lobster(100,0.9,0.9)


Graph IO
========

Reading a graph from a file
---------------------------

>>> G=tetrahedral_graph()

Write to adjacency list format

>>> write_adjlist(G, "tetrahedral.adjlist")

Read from adjacency list format

>>> H=read_adjlist("tetrahedral.adjlist")

Write to edge list format

>>> write_edgelist(G, "tetrahedral.edgelist")

Read from edge list format

>>> H=read_edgelist("tetrahedral.edgelist")


See also `Interfacing with other tools`_ below for
how to draw graphs with matplotlib or graphviz.

Graphs with multiple edges and self-loops
=========================================

See the XGraph and XDiGraph classes. For example, to build Euler's famous 
graph of the bridges of Konigsberg over the Pregel river,
one can use:

>>> K=XGraph(name="Konigsberg", multiedges=True, selfloops=False) 
>>> K.add_edges_from([("A","B","Honey Bridge"),
...                   ("A","B","Blacksmith's Bridge"),
...                   ("A","C","Green Bridge"),
...                   ("A","C","Connecting Bridge"),
...                   ("A","D","Merchant's Bridge"),
...                   ("C","D","High Bridge"),
...                   ("B","D","Wooden Bridge")])
>>> K.degree("A")
5



Directed Graphs
===============

The DiGraph class provides operations common to digraphs (graphs with
directed edges). A subclass of Graph, Digraph adds the following
methods to those of Graph:

    - out_edges
    - out_edges_iter
    - in_edges
    - in_edges_iter
    - successors=in_neighbors=neighbors
    - successors_iter=in_neighbors_iter=neighbors_iter
    - predecessors=out_neighbors
    - predecessors_iter=out_neighbors_iter
    - out_degree
    - out_degree_iter
    - in_degree
    - in_degree_iter

See networkx.DiGraph for more documentation. 


Interfacing with other tools
============================

NetworkX provides interfaces to matplotlib and graphviz for graph
layout (node and edge positioning) and drawing. We also use matplotlib for 
graph spectra and in some drawing operations. Without either, one can
still use the basic graph-related functions.

See the graph drawing section for details on how to install and use 
these tools.

Matplotlib
----------

>>> G=tetrahedral_graph()
>>> draw(G)  


Graphviz
--------

>>> G=tetrahedral_graph()
>>> write_dot(G,"tetrahedral.dot")


Specialized Topics
==================

Graphs composed of general objects
----------------------------------

For most applications, nodes will have string or integer labels.
The power of Python ("everything is an object") allows us to construct 
graphs with ANY hashable object as a node. 
(The Python object None is not allowed as a node). 
Note however that this will not work with non-Python
datastructures, e.g. building a graph on a wrapped Python version
of graphviz).

For example, one can construct a graph with Python
mathematical functions as nodes, and where two mathematical
functions are connected if they are in the same chapter in some
Handbook of Mathematical Functions. E.g.

>>> from math import *
>>> G=Graph()
>>> G.add_node(acos)
>>> G.add_node(sinh)
>>> G.add_node(cos)
>>> G.add_node(tanh)
>>> G.add_edge(acos,cos)
>>> G.add_edge(sinh,tanh)
>>> sorted(G.nodes())
[<built-in function acos>, <built-in function cos>, <built-in function sinh>, <built-in function tanh>]

As another example, one can build (meta) graphs using other graphs as
the nodes.

We have found this power quite useful, but its abuse
can lead to unexpected surprises unless one is familiar with Python. If
in doubt, consider using convert_node_labels_to_integers to obtain
a more traditional graph with integer labels.

Imbedding general objects onto edges
------------------------------------

An XGraph and XDiGraph object allows arbitrary objects to be
associated with an edge. In these classes edges are 3-tuples (n1,n2,x),
representing an edge between nodes n1 and n2 that is decorated with
the object x (not necessarily hashable). For example, n1 and n2 can be
protein objects from the RCSB Protein Data Bank, and x can refer to an XML
record of a publication detailing experimental observations of their
interaction. These classes are still in the experimental stage, with
not all the graph-related functions and operations tested on them. Use
with caution and tell us if you find them useful.


Unit tests
----------

For most modules, say base.py, the command "python base.py" will run
several unit tests in the networkx/tests subdirectory. This requires the use
of Python 2.4 or later. To run all the unit tests, run "python setup.py test"
in the base directory or  run "python test.py" in the networkx/tests 
subdirectory.


Not everything is an object
---------------------------

NX developed from the need to analyze dynamics on a diverse collection
of large networks and we have thus far refused to objectify all the
mathematical structures of graph theory down to the atomic
level. Neither nodes nor edges are implemented as Classes.  A node can
be any hashable object (except None), and an edge is a 2-tuple (n1,n2)
of nodes (in the case of Graph and DiGraph) or a 3-tuple (n1,n2,x) (in
the case of XGraph and XDiGraph) consisting of two nodes and an object
x decorating that edge.


References
==========

.. [BA02] R. Albert and A.-L. Barabási, "Statistical mechanics of complex
   networks", Reviews of Modern Physics, 74, pp. 47-97, 2002.
   (Preprint available online at http://citeseer.ist.psu.edu/442178.html
   or http://arxiv.org/abs/cond-mat/0106096)


.. [Bollobas01] B. Bollobás, "Random Graphs", Second Edition,
   Cambridge University Press, 2001.

.. [BE05] U. Brandes and T. Erlebach, "Network Analysis:
   Methodological Foundations", Lecture Notes in Computer Science, 
   Volume 3418, Springer-Verlag, 2005.

.. [Diestel97] R. Diestel, "Graph Theory", Springer-Verlag, 1997.
   (A free electronic version is available at
   http://www.math.uni-hamburg.de/home/diestel/books/graph.theory/download.html)


.. [DM03] S.N. Dorogovtsev and J.F.F. Mendes, "Evolution of Networks",
   Oxford University Press, 2003.


.. [Langtangen04] H.P. Langtangen, "Python Scripting for Computational
    Science.", Springer Verlag Series in Computational Science and
    Engineering, 2004. 


.. [Martelli03]  A. Martelli, "Python in a Nutshell", O'Reilly Media
   Inc, 2003. (A useful guide to the language is available at 
   http://www.oreilly.com/catalog/pythonian/chapter/ch04.pdf)


.. [Newman03] M.E.J. Newman, "The Structure and Function of Complex
   Networks", SIAM Review, 45, pp. 167-256, 2003. (Available online at 
   http://epubs.siam.org/sam-bin/dbq/article/42480 ) 


.. [Sedgewick02] R. Sedgewick, "Algorithms in C: Parts 1-4: 
   Fundamentals, Data Structure, Sorting, Searching", Addison Wesley
   Professional, 3rd ed., 2002.


.. [Sedgewick01] R. Sedgewick, "Algorithms in C, Part 5: Graph Algorithms",
   Addison Wesley Professional, 3rd ed., 2001.


.. [West01] D. B. West, "Introduction to Graph Theory", Prentice Hall,
    2nd ed., 2001.