Graph::Base - graph base class
$d2 = new Graph::Directed;
$u = new Graph::Undirected;
You create new graphs by calling the C<new> constructors of classes
C<Graph>, C<Graph::Directed>, and C<Graph::Undirected>. The classes
C<Graph> and C<Graph::Directed> are identical. After creating the
graph you can modify and explore the graph with following methods.
Returns a new graph $G with the optional vertices @V.
$G->add_vertices(@_) if @_;
$G = $G->add_vertices(@v)
Adds the vertices to the graph $G, returns the graph.
@
{ $G->{ V
} }{ @v } = @v;
Adds the vertex $v to the graph $G, returns the graph.
return $G->add_vertices($v);
In list context returns the vertices @V of the graph $G.
In scalar context returns the number of the vertices.
my @V = exists $G->{ V
} ?
sort values %{ $G->{ V
} } : ();
In list context returns a list which contains the vertex
of the vertices @v if the vertex exists in the graph $G
and undef if it doesn't. In scalar context returns the
number of the existing vertices.
map { exists $G->{ V
}->{ $_ } ?
$_ : undef } @_ :
grep { exists $G->{ V
}->{ $_ } } @_ ;
Returns true if the vertex $v exists in
the graph $G and false if it doesn't.
return defined $v && exists $G->{ V
} && exists $G->{ V
}->{ $v };
Returns the vertex $v if the vertex exists in the graph $G
return defined $v && $G->{ V
}->{ $v };
Set the directedness of the graph $G to $d or return the
current directedness. Directedness defaults to true.
my $o = $G->{ D
}; # Old directedness.
while (my ($u, $v) = splice(@E, 0, 2)) {
return bless $G, 'Graph::Directed'; # Re-bless.
return $G->undirected(not $d);
Set the undirectedness of the graph $G to $u or return the
current undirectedness. Undirectedness defaults to false.
$G->{ D
} = 1 unless defined $G->{ D
};
my $o = $G->{ D
}; # Old directedness.
while (my ($u, $v) = splice(@E, 0, 2)) {
# Throw away duplicate edges.
$G->delete_edge($u, $v) if exists $E{$v}->{$u};
return bless $G, 'Graph::Undirected'; # Re-bless.
return $G->directed(not $u);
$b = $G->has_edge($u, $v)
Return true if the graph $G has the edge between
return exists $G->{ Succ
}->{ $u }->{ $v } ||
($G->undirected && exists $G->{ Succ
}->{ $v }->{ $u });
$G->has_edges($u1, $v1, $u2, $v2, ...)
In list context returns a list which contains true for each
edge in the graph $G defined by the vertices $u1, $v1, ...,
and false for each non-existing edge. In scalar context
returns the number of the existing edges.
while (my ($u, $v) = splice(@_, 0, 2)) {
push @e, $G->has_edge($u, $v);
return wantarray ?
@e : grep { $_ } @e;
$G->has_path($u, $v, ...)
Return true if the graph $G has the cycle defined by
the vertices $u, $v, ..., false otherwise.
return 0 unless $G->has_edge($u, $v);
$G->has_cycle($u, $v, ...)
Return true if the graph $G has the cycle defined by
the vertices $u, $v, ...,false otherwise.
return $G->has_path(@_, $_[0]); # Just wrap around.
# $G->_union_vertex_set($u, $v)
# Adds the vertices $u and $v in the graph $G to the same vertex set.
my $su = $G->vertex_set( $u );
my $sv = $G->vertex_set( $v );
my $ru = $G->{ VertexSetRank
}->{ $su };
my $rv = $G->{ VertexSetRank
}->{ $sv };
if ( $ru < $rv ) { # Union by rank (weight balancing).
$G->{ VertexSetParent
}->{ $su } = $sv;
$G->{ VertexSetParent
}->{ $sv } = $su;
$G->{ VertexSetRank
}->{ $sv }++ if $ru == $rv;
Returns the vertex set of the vertex $v in the graph $G.
A "vertex set" is represented by its parent vertex.
if ( exists $G->{ VertexSetParent
}->{ $v } ) {
$G->{ VertexSetParent
}->{ $v } =
$G->vertex_set( $G->{ VertexSetParent
}->{ $v } )
if $v ne $G->{ VertexSetParent
}->{ $v };
$G->{ VertexSetParent
}->{ $v } = $v;
$G->{ VertexSetRank
}->{ $v } = 0;
return $G->{ VertexSetParent
}->{ $v };
$G = $G->add_edge($u, $v)
Adds the edge defined by the vertices $u, $v, to the graph $G.
Also implicitly adds the vertices. Returns the graph.
$G->_union_vertex_set( $u, $v );
push @
{ $G->{ Succ
}->{ $u }->{ $v } }, $v;
push @
{ $G->{ Pred
}->{ $v }->{ $u } }, $u;
$G = $G->add_edges($u1, $v1, $u2, $v2, ...)
Adds the edge defined by the vertices $u1, $v1, ...,
to the graph $G. Also implicitly adds the vertices.
while (my ($u, $v) = splice(@_, 0, 2)) {
$G->add_path($u, $v, ...)
Adds the path defined by the vertices $u, $v, ...,
to the graph $G. Also implicitly adds the vertices.
$G = $G->add_cycle($u, $v, ...)
Adds the cycle defined by the vertices $u, $v, ...,
to the graph $G. Also implicitly adds the vertices.
$G->add_path(@_, $_[0]); # Just wrap around.
# @s = $G->_successors($v)
# (INTERNAL USE ONLY, use only on directed graphs)
# Returns the successor vertices @s of the vertex
defined $G->{ Succ
}->{ $v } ?
map { @
{ $G->{ Succ
}->{ $v }->{ $_ } } }
sort keys %{ $G->{ Succ
}->{ $v } } :
# @p = $G->_predecessors($v)
# (INTERNAL USE ONLY, use only on directed graphs)
# Returns the predecessor vertices @p of the vertex $v
defined $G->{ Pred
}->{ $v } ?
map { @
{ $G->{ Pred
}->{ $v }->{ $_ } } }
sort keys %{ $G->{ Pred
}->{ $v } } :
Returns the neighbor vertices of the vertex in the graph.
(Also 'neighbours' works.)
my @n = ($G->_successors($v), $G->_predecessors($v));
*neighbours
= \
&neighbors
; # Keep both sides of the Atlantic happy.
Returns the successor vertices of the vertex in the graph.
return $G->directed ?
$G->_successors($v) : $G->neighbors($v);
@p = $G->predecessors($v)
Returns the predecessor vertices of the vertex in the graph.
return $G->directed ?
$G->_predecessors($v) : $G->neighbors($v);
Returns the edges leading out of the vertex $v in the graph $G.
In list context returns the edges as ($start_vertex, $end_vertex)
pairs. In scalar context returns the number of the edges.
return () unless $G->has_vertex($v);
my @e = $G->_edges($v, undef);
return wantarray ?
@e : @e / 2;
Returns the edges leading into the vertex $v in the graph $G.
In list context returns the edges as ($start_vertex, $end_vertex)
pairs; in scalar context returns the number of the edges.
return () unless $G->has_vertex($v);
my @e = $G->_edges(undef, $v);
return wantarray ?
@e : @e / 2;
Returns the edges between the vertices $u and $v, or if $v
is undefined, the edges leading into or out of the vertex $u,
or if $u is undefined, returns all the edges, of the graph $G.
In list context returns the edges as a list of
$start_vertex, $end_vertex pairs; in scalar context
returns the number of the edges.
return () if defined $v and not $G->has_vertex($v);
($G->in_edges($u), $G->out_edges($u)) ) :
return wantarray ?
@e : @e / 2;
$G = $G->delete_edge($u, $v)
Deletes an edge defined by the vertices $u, $v from the graph $G.
Note that the edge need not actually exist.
pop @
{ $G->{ Succ
}->{ $u }->{ $v } };
pop @
{ $G->{ Pred
}->{ $v }->{ $u } };
delete $G->{ Succ
}->{ $u }->{ $v }
unless @
{ $G->{ Succ
}->{ $u }->{ $v } };
delete $G->{ Pred
}->{ $v }->{ $u }
unless @
{ $G->{ Pred
}->{ $v }->{ $u } };
delete $G->{ Succ
}->{ $u }
unless keys %{ $G->{ Succ
}->{ $u } };
delete $G->{ Pred
}->{ $v }
unless keys %{ $G->{ Pred
}->{ $v } };
$G = $G->delete_edges($u1, $v1, $u2, $v2, ..)
Deletes edges defined by the vertices $u1, $v1, ...,
Note that the edges need not actually exist.
while (my ($u, $v) = splice(@_, 0, 2)) {
while (($u, $v) = splice(@e, 0, 2)) {
$G = $G->delete_path($u, $v, ...)
Deletes a path defined by the vertices $u, $v, ..., from the graph $G.
Note that the path need not actually exist. Returns the graph.
$G = $G->delete_cycle($u, $v, ...)
Deletes a cycle defined by the vertices $u, $v, ..., from the graph $G.
Note that the cycle need not actually exist. Returns the graph.
$G->delete_path(@_, $_[0]); # Just wrap around.
$G = $G->delete_vertex($v)
Deletes the vertex $v and all its edges from the graph $G.
Note that the vertex need not actually exist.
delete $G->{ V
}->{ $v };
$G = $G->delete_vertices(@v)
Deletes the vertices @v and all their edges from the graph $G.
Note that the vertices need not actually exist.
Returns the in-degree of the vertex $v in the graph $G,
or, if $v is undefined, the total in-degree of all the
vertices of the graph, or undef if the vertex doesn't
return undef unless $G->has_vertex($v);
return scalar $G->in_edges($v);
foreach my $v ($G->vertices) {
$in += $G->in_degree($v);
return scalar $G->edges($v);
Returns the out-degree of the vertex $v in the graph $G,
or, if $v is undefined, the total out-degree of all the
vertices of the graph, of undef if the vertex doesn't
return undef unless $G->has_vertex($v);
return scalar $G->out_edges($v);
foreach my $v ($G->vertices) {
$out += $G->out_degree($v);
return scalar $G->edges($v);
Returns the degree of the vertex $v in the graph $G
or, if $v is undefined, the total degree of all the
vertices of the graph, or undef if the vertex $v
doesn't exist in the graph.
return undef unless $G->has_vertex($v);
return $G->in_degree($v) - $G->out_degree($v);
foreach my $v ($G->vertices) {
Returns the average degree of the vertices of the graph $G.
return $V ?
$G->degree / $V : 0;
$b = $G->is_source_vertex($v)
Returns true if the vertex $v is a source vertex of the graph $G.
$G->in_degree($v) == 0 && $G->out_degree($v) > 0;
$b = $G->is_sink_vertex($v)
Returns true if the vertex $v is a sink vertex of the graph $G.
$G->in_degree($v) > 0 && $G->out_degree($v) == 0;
$b = $G->is_isolated_vertex($v)
Returns true if the vertex $v is a isolated vertex of the graph $G.
$G->in_degree($v) == 0 && $G->out_degree($v) == 0;
$b = $G->is_exterior_vertex($v)
Returns true if the vertex $v is a exterior vertex of the graph $G.
$G->in_degree($v) == 0 xor $G->out_degree($v) == 0;
$b = $G->is_interior_vertex($v)
Returns true if the vertex $v is a interior vertex of the graph $G.
$G->in_degree($v) && $G->out_degree($v);
=item is_self_loop_vertex
$b = $G->is_self_loop_vertex($v)
Returns true if the vertex $v is a self-loop vertex of the graph $G.
sub is_self_loop_vertex
{
exists $G->{ Succ
}->{ $v }->{ $v };
Returns the source vertices @s of the graph $G.
return grep { $G->is_source_vertex($_) } $G->vertices;
Returns the sink vertices @s of the graph $G.
return grep { $G->is_sink_vertex($_) } $G->vertices;
@i = $G->isolated_vertices
Returns the isolated vertices @i of the graph $G.
return grep { $G->is_isolated_vertex($_) } $G->vertices;
@e = $G->exterior_vertices
Returns the exterior vertices @e of the graph $G.
return grep { $G->is_exterior_vertex($_) } $G->vertices;
@i = $G->interior_vertices
Returns the interior vertices @i of the graph $G.
return grep { $G->is_interior_vertex($_) } $G->vertices;
@s = $G->self_loop_vertices
Returns the self-loop vertices @s of the graph $G.
return grep { $G->is_self_loop_vertex($_) } $G->vertices;
($sparse, $dense, $complete) = $G->density_limits
Returns the density limits for the number of edges
in the graph $G. Note that reaching $complete edges
does not really guarantee completeness because we
can have multigraphs. The limit of sparse is less
than 1/4 of the edges of the complete graph, the
limit of dense is more than 3/4 of the edges of the
$M = $M / 2 if $G->undirected;
return ($M/4, 3*$M/4, $M);
Returns the density $d of the graph $G.
my ($sparse, $dense, $complete) = $G->density_limits;
return $complete ?
$G->edges / $complete : 0;
Returns true if the graph $G is sparse.
my ($sparse, $dense, $complete) = $G->density_limits;
return $complete ?
$G->edges / $complete <= $dense : 1;
Returns true if the graph $G is dense.
my ($sparse, $dense, $complete) = $G->density_limits;
return $complete ?
$G->edges / $complete >= $dense : 0;
Returns a new complete graph $C corresponding to the graph $G.
$C->add_edge($u, $v) unless $u eq $v;
next if $u eq $v or $E{$u}->{$v} || $E{$v}->{$u};
$C->directed($G->directed);
Returns a new complement graph $C corresponding to the graph $G.
while (my ($u, $v) = splice(@E, 0, 2)) {
Returns a new graph $C corresponding to the graph $G.
my $C = (ref $G)->new($G->vertices);
while (my ($u, $v) = splice(@E, 0, 2)) {
$C->directed($G->directed);
Returns a new transpose graph $T corresponding to the graph $G.
return $G->copy if $G->undirected;
my $T = (ref $G)->new($G->vertices);
while (my ($u, $v) = splice(@E, 0, 2)) {
# $s = $G->_stringify($connector, $separator)
# Returns a string representation of the graph $G.
# The edges are represented by $connector and edges/isolated
# vertices are represented by $separator.
my ($G, $connector, $separator) = @_;
my @e = map { [ $_ ] } $G->isolated_vertices;
while (my ($u, $v) = splice(@E, 0, 2)) {
join($connector, $_->[0], $_->[1]) :
sort { $a->[0] cmp $b->[0] || @
$a <=> @
$b } @e);
$G->set_attribute($attribute, $value)
$G->set_attribute($attribute, $v, $value)
$G->set_attribute($attribute, $u, $v, $value)
Sets the $attribute of graph/vertex/edge to $value
but only if the vertex/edge already exists. Returns
true if the attribute is set successfully, false if not.
return 0 unless $G->has_vertex($u);
return 0 unless $G->has_edge($u, $v);
$G->{ Attr
}->{ E
}->{ $u }->{ $v }->{ $attribute } = $value;
$G->{ Attr
}->{ E
}->{ $v }->{ $u }->{ $attribute } = $value
$G->{ Attr
}->{ V
}->{ $u }->{ $attribute } = $value;
$G->{ Attr
}->{ G
}->{ $attribute } = $value;
$value = $G->get_attribute($attribute)
$value = $G->get_attribute($attribute, $v)
$value = $G->get_attribute($attribute, $u, $v)
Returns the $value of $attribute of graph/vertex/edge.
unless exists $G->{ Attr
}->{ E
};
my $E = $G->{ Attr
}->{ E
};
return $E->{ $u }->{ $v }->{ $attribute };
unless exists $G->{ Attr
}->{ E
};
return $E->{ $u }->{ $v }->{ $attribute }
if exists $E->{ $u }->{ $v }->{ $attribute };
return $E->{ $v }->{ $u }->{ $attribute };
return $G->{ Attr
}->{ V
}->{ $u }->{ $attribute };
return $G->{ Attr
}->{ G
}->{ $attribute };
$value = $G->has_attribute($attribute)
$value = $G->has_attribute($attribute, $v)
$value = $G->has_attribute($attribute, $u, $v)
Returns the $value of $attribute of graph/vertex/edge.
unless exists $G->{ Attr
}->{ E
};
my $E = $G->{ Attr
}->{ E
};
return exists $E->{ $u }->{ $v }->{ $attribute };
return exists $E->{ $u }->{ $v }->{ $attribute } or
exists $E->{ $v }->{ $u }->{ $attribute };
exists $G->{ Attr
}->{ V
}->{ $u }->{ $attribute };
exists $G->{ Attr
}->{ G
}->{ $attribute };
%attributes = $G->get_attributes()
%attributes = $G->get_attributes($v)
%attributes = $G->get_attributes($u, $v)
Returns as a hash all the attribute names and values
return ( ) unless exists $G->{ Attr
};
return exists $G->{ Attr
}->{ E
} &&
exists $G->{ Attr
}->{ E
}->{ $u } &&
exists $G->{ Attr
}->{ E
}->{ $u }->{ $v } ?
%{ $G->{ Attr
}->{ E
}->{ $u }->{ $v } } :
return exists $G->{ Attr
}->{ V
} &&
exists $G->{ Attr
}->{ V
}->{ $u } ?
%{ $G->{ Attr
}->{ V
}->{ $u } } : ( );
return exists $G->{ Attr
}->{ G
} ?
%{ $G->{ Attr
}->{ G
} } : ( );
$G->delete_attribute($attribute)
$G->delete_attribute($attribute, $v)
$G->delete_attribute($attribute, $u, $v)
Deletes the $attribute of graph/vertex/edge.
unless exists $G->{ Attr
}->{ E
};
my $E = $G->{ Attr
}->{ E
};
delete $E->{ $u }->{ $v }->{ $attribute };
delete $E->{ $v }->{ $u }->{ $attribute };
delete $E->{ $v }->{ $u }->{ $attribute };
delete $G->{ Attr
}->{ V
}->{ $u }->{ $attribute };
delete $G->{ Attr
}->{ G
}->{ $attribute };
$G->delete_attributes($v)
$G->delete_attributes($u, $v)
Deletes all the attributes of graph/vertex/edge.
delete $G->{ Attr
}->{ E
}->{ $u }->{ $v };
delete $G->{ Attr
}->{ V
}->{ $u };
delete $G->{ Attr
}->{ G
};
$G->add_weighted_edge($u, $w, $v, $a)
Adds in the graph $G an edge from vertex $u to vertex $v
and the edge attribute 'weight' set to $w.
my ($G, $u, $w, $v, $a) = @_;
$G->set_attribute('weight', $u, $v, $w);
$G->add_weighted_edges($u1, $w1, $v1, $u2, $w2, $v2, ...)
Adds in the graph $G the weighted edges.
while (my ($u, $w, $v) = splice(@_, 0, 3)) {
$G->add_weighted_edge($u, $w, $v);
$G->add_weighted_path($v1, $w1, $v2, $w2, ..., $wnm1, $vn)
Adds in the graph $G the n edges defined by the path $v1 ... $vn
with the n-1 'weight' attributes $w1 ... $wnm1
while (my ($w, $v) = splice(@_, 0, 2)) {
$G->add_weighted_edge($u, $w, $v);
Returns Kruskal's Minimum Spanning Tree (as a graph) of
the graph $G based on the 'weight' attributes of the edges.
(Needs the ->vertex_set() method.)
while (($u, $v) = splice(@E, 0, 2)) {
$w = $G->get_attribute('weight', $u, $v);
next unless defined $w; # undef weight == infinitely heavy
$MST->directed( $G->directed );
foreach my $e ( sort { $a->[ 2 ] <=> $b->[ 2 ] } @W ) {
$MST->add_weighted_edge( $u, $w, $v )
unless $MST->vertex_set( $u ) eq $MST->vertex_set( $v );
@C = $G->edge_classify(%param)
Returns the edge classification as a list where each element
is a triplet [$u, $v, $class] the $u, $v being the vertices
of an edge and $class being the class. The %param can be
used to control the search.
# Freshly seen successors make for tree edges.
push @
{ $T->{ edge_class_list
} },
if ( $T->{ G
}->directed ) {
$class = 'cross'; # Default for directed non-tree edges.
unless ( exists $T->{ vertex_finished
}->{ $v } ) {
} elsif ( $T->{ vertex_found
}->{ $u } <
$T->{ vertex_found
}->{ $v }) {
# No cross nor forward edges in
# an undirected graph, by definition.
push @
{ $T->{ edge_class_list
} }, [ $u, $v, $class ];
unseen_successor
=> $unseen_successor,
seen_successor
=> $seen_successor,
return @
{ $d->{ edge_class_list
} };
Returns the vertices of the graph $G sorted topologically.
my $d = Graph
::DFS
->new($G);
reverse $d->postorder; # That's it.
# $s = $G->_strongly_connected
# Returns a graph traversal object that can be used for
# strong connection computations.
sub _strongly_connected
{
# Pick the potential roots in their DFS postorder.
strong_root_order
=> [ reverse Graph
::DFS
->new($G)->postorder ],
shift @
{ $param{ strong_root_order
} }) {
return $root if exists $T->{ pool
}->{ $root };
=item strongly_connected_components
@S = $G->strongly_connected_components
Returns the strongly connected components @S of the graph $G
as a list of anonymous lists of vertices, each anonymous list
containing the vertices belonging to one strongly connected
sub strongly_connected_components
{
my $T = $G->_strongly_connected;
my %R = $T->_vertex_roots;
# Clump together vertices having identical root vertices.
while (my ($v, $r) = each %R) { push @
{ $C[ $r ] }, $v }
=item strongly_connected_graph
$T = $G->strongly_connected_graph
Returns the strongly connected graph $T of the graph $G.
The names of the strongly connected components are
formed from their constituent vertices by concatenating
their names by '+'-characters: "a" and "b" --> "a+b".
sub strongly_connected_graph
{
my $T = $G->_strongly_connected;
my %R = $T->_vertex_roots;
my @C; # We're not calling the strongly_connected_components()
# method because we will need also the %R.
# Create the strongly connected components.
while (my ($v, $r) = each %R) { push @
{ $C[$r] }, $v }
foreach my $c (@C) { $c = join("+", @
$c) }
$C->directed( $G->directed );
# Copy the edges between strongly connected components.
while (my ($u, $v) = splice(@E, 0, 2)) {
if ($R{ $u } != $R{ $v }) {
$C->add_edge( $C[ $R{ $u } ], $C[ $R{ $v } ] );
} elsif ($edge_cnt == 0) {
$C->add_vertex(join("+", keys %n));
=item APSP_Floyd_Warshall
$APSP = $G->APSP_Floyd_Warshall
Returns the All-pairs Shortest Paths graph of the graph $G
computed using the Floyd-Warshall algorithm and the attribute
The returned graph has an edge for each shortest path.
An edge has attributes "weight" and "path"; for the length of
the shortest path and for the path (an anonymous list) itself.
sub APSP_Floyd_Warshall
{
# Compute the vertex <-> index mappings.
# Initialize the predecessor matrix @P and the weight matrix @W.
# (The graph is converted into adjacency-matrix representation.)
# (The matrix is a list of lists.)
foreach my $i ( 0..$#V ) { $W[ $i ][ $i ] = 0 }
while ( my ($u, $v) = splice(@E, 0, 2) ) {
my ( $ui, $vi ) = ( $V2I{ $u }, $V2I{ $v } );
$P[ $ui ][ $vi ] = $ui unless $ui == $vi;
$W[ $ui ][ $vi ] = $G->get_attribute( 'weight', $u, $v );
for ( my $k = 0; $k < @V; $k++ ) {
my (@nP, @nW); # new @P, new @W
for ( my $i = 0; $i < @V; $i++ ) {
for ( my $j = 0; $j < @V; $j++ ) {
my $w_ij = $W[ $i ][ $j ];
my $w_ik_kj = $W[ $i ][ $k ] + $W[ $k ][ $j ]
if defined $W[ $i ][ $k ] and
# Choose the minimum of w_ij and w_ik_kj.
if ( defined $w_ik_kj ) {
if ( $w_ij <= $w_ik_kj ) {
$nP[ $i ][ $j ] = $P[ $i ][ $j ];
$nP[ $i ][ $j ] = $P[ $k ][ $j ];
$nW[ $i ][ $j ] = $w_ik_kj;
$nP[ $i ][ $j ] = $P[ $i ][ $j ];
} elsif ( defined $w_ik_kj ) {
$nP[ $i ][ $j ] = $P[ $k ][ $j ];
$nW[ $i ][ $j ] = $w_ik_kj;
@P = @nP; @W = @nW; # Update the predecessors and weights.
# Now construct the APSP graph.
my $APSP = (ref $G)->new;
$APSP->directed( $G->directed ); # Copy the directedness.
# Convert the adjacency-matrix representation
# into a Graph (adjacency-list representation).
for ( my $i = 0; $i < @V; $i++ ) {
for ( my $j = 0; $j < @V; $j++ ) {
$APSP->add_weighted_edge( $iv, 0, $iv );
$APSP->set_attribute("path", $iv, $iv, [ $iv ]);
next unless defined $W[ $i ][ $j ];
$APSP->add_weighted_edge( $iv, $W[ $i ][ $j ], $jv );
if ( $P[ $i ][ $j ] != $i ) {
my $k = $P[ $i ][ $j ]; # Walk back the path.
$k = $P[ $i ][ $k ]; # Keep walking.
$APSP->set_attribute( "path", $iv, $jv, [ $iv, reverse @path ] );
=item TransitiveClosure_Floyd_Warshall
$TransitiveClosure = $G->TransitiveClosure_Floyd_Warshall
Returns the Transitive Closure graph of the graph $G computed
using the Floyd-Warshall algorithm.
The resulting graph has an edge between each *ordered* pair of
vertices in which the second vertex is reachable from the first.
sub TransitiveClosure_Floyd_Warshall
{
# Compute the vertex <-> index mappings.
# Initialize the closure matrix @C.
# (The graph is converted into adjacency-matrix representation.)
# (The matrix is a bit matrix. Well, a list of bit vectors.)
foreach my $i ( 0..$#V ) { vec( $C[ $i ], $i, 1 ) = 1 }
while ( my ($u, $v) = splice(@E, 0, 2) ) {
vec( $C[ $V2I{ $u } ], $V2I{ $v }, 1 ) = 1
for ( my $k = 0; $k < @V; $k++ ) {
my @nC = ( '' ) x
@V; # new @C
for ( my $i = 0; $i < @V; $i++ ) {
for ( my $j = 0; $j < @V; $j++ ) {
vec( $nC[ $i ], $j, 1 ) =
vec( $C[ $i ], $k, 1 ) & vec( $C[ $k ], $j, 1 );
@C = @nC; # Update the closure.
# Now construct the TransitiveClosure graph.
my $TransitiveClosure = (ref $G)->new;
$TransitiveClosure->directed( $G->directed );
# Convert the (closure-)adjacency-matrix representation
# into a Graph (adjacency-list representation).
for ( my $i = 0; $i < @V; $i++ ) {
for ( my $j = 0; $j < @V; $j++ ) {
$TransitiveClosure->add_edge( $I2V[ $i ], $I2V[ $j ] )
if vec( $C[ $i ], $j, 1 );
return $TransitiveClosure;
=item articulation points
@A = $G->articulation_points(%param)
Returns the articulation points (vertices) @A of the graph $G.
The %param can be used to control the search.
sub articulation_points
{
my $ap = $T->{ vertex_found
}->{ $u };
my @S = @
{ $T->{ active_list
} }; # Current stack.
$T->{ articulation_point
}->{ $u } = $ap
unless exists $T->{ articulation_point
}->{ $u };
# Walk back the stack marking the active DFS branch
# (below $u) as belonging to the articulation point $ap.
for ( my $i = 1; $i < @S; $i++ ) {
$T->{ articulation_point
}->{ $v } = $ap
if not exists $T->{ articulation_point
}->{ $v } or
$ap < $T->{ articulation_point
}->{ $v };
# We need to know the number of children for root vertices.
$T->{ articulation_children
}->{ $u }++;
# If the $v is still active, articulate it.
$articulate->( $v, $T ) if exists $T->{ active_pool
}->{ $v };
articulate
=> $articulate,
unseen_successor
=> $unseen_successor,
seen_successor
=> $seen_successor,
# Now we need to find (the indices of) unique articulation points
# and map them back to vertices.
foreach my $v ( $G->vertices ) {
$ap{ $d->{ articulation_point
}->{ $v } } = $v;
$vf[ $d->{ vertex_found
}->{ $v } ] = $v;
%ap = map { ( $vf[ $_ ], $_ ) } keys %ap;
# DFS tree roots are articulation points only
# iff they have more than one children.
foreach my $r ( $d->roots ) {
delete $ap{ $r } if $d->{ articulation_children
}->{ $r } < 2;
Returns true is the graph $G is biconnected
(has no articulation points), false otherwise.
return $G->articulation_points == 0;
$v = $G->largest_out_degree( @V )
Selects the vertex $v from the vertices @V having
the largest out degree in the graph $G.
my $O = $G->out_degree($L);
my $o = $G->out_degree($e);
# $G->_heap_init($heap, $u, \%in_heap, \%weight, \%parent)
# Initializes the $heap with the vertex $u as the initial
# vertex, its weight being zero, and marking all vertices
# of the graph $G to be $in_heap,
my ($G, $heap, $u, $in_heap, $W, $P) = @_;
foreach my $v ( $G->vertices ) {
my $e = Graph
::HeapElem
->new( $v, $W, $P );
Returns Prim's Minimum Spanning Tree (as a graph) of
the graph $G based on the 'weight' attributes of the edges.
The optional start vertex is $u, if none is given, a hopefully
good one (a vertex with a large out degree) is chosen.
$u = $G->largest_out_degree( $G->vertices ) unless defined $u;
my $heap = Heap
::Fibonacci
->new;
my ( %in_heap, %weight, %parent );
$G->_heap_init( $heap, $u, \
%in_heap, \
%weight, \
%parent );
# Walk the edges at the current BFS front
# in the order of their increasing weight.
while ( defined $heap->minimum ) {
$u = $heap->extract_minimum;
delete $in_heap{ $u->vertex };
# Now extend the BFS front.
foreach my $v ( $G->successors( $u->vertex ) ) {
if ( defined( $v = $in_heap{ $v } ) ) {
my $nw = $G->get_attribute( 'weight',
$u->vertex, $v->vertex );
if ( not defined $ow or $nw < $ow ) {
$v->parent( $u->vertex );
$heap->decrease_key( $v );
foreach my $v ( $G->vertices ) {
$MST->add_weighted_edge( $v, $weight{ $v }, $parent{ $v } )
if defined $parent{ $v };
# $SSSP = $G->_SSSP_construct( $s, $W, $P );
# Return the SSSP($s) graph of graph $G based on the computed
# anonymous hashes for weights and parents: $W and $P.
# The vertices of the graph will have two attributes: "weight",
# which tells the length of the shortest single-source path,
# and "path", which is an anymous list containing the path.
my ($G, $s, $W, $P ) = @_;
my $SSSP = (ref $G)->new;
foreach my $u ( $G->vertices ) {
$SSSP->set_attribute( "weight", $u, $W->{ $u } || 0 );
if ( defined $P->{ $u } ) {
$SSSP->add_edge($P->{ $u }, $u );
$SSSP->set_attribute( "weight", $P->{ $u }, $u, $G->get_attribute("weight",$P->{ $u }, $u) || 0 );
if ( $P->{ $u } ne $s ) {
while ( defined $v && exists $P->{ $v } && $v ne $s ) {
$SSSP->set_attribute( "path", $u, [ reverse @path ] );
$SSSP = $G->SSSP_Dijkstra($s)
Returns the Single-source Shortest Paths (as a graph)
of the graph $G starting from the vertex $s using Dijktra's
my $heap = Heap
::Fibonacci
->new;
my ( %in_heap, %weight, %parent );
# The other weights are by default undef (infinite).
$G->_heap_init($heap, $s, \
%in_heap, \
%weight, \
%parent );
# Walk the edges at the current BFS front
# in the order of their increasing weight.
while ( defined $heap->minimum ) {
my $u = $heap->extract_minimum;
delete $in_heap{ $u->vertex };
# Now extend the BFS front.
foreach my $v ( $G->successors( $u->vertex ) ) {
if ( defined( $v = $in_heap{ $v } ) ) {
$G->get_attribute( 'weight', $u->vertex, $v->vertex ) +
($uw || 0); # The || 0 helps for undefined $uw.
# Relax the edge $u - $v.
if ( not defined $ow or $ow > $nw ) {
$v->parent( $u->vertex );
$heap->decrease_key( $v );
return $G->_SSSP_construct( $s, \
%weight, \
%parent );
$SSSP = $G->SSSP_Bellman_Ford($s)
Returns the Single-source Shortest Paths (as a graph)
of the graph $G starting from the vertex $s using Bellman-Ford
SSSP algorithm. If there are one or more negatively weighted
foreach ( 1..$V ) { # |V|-1 times (*not* |V| times)
while (my ($u, $v) = splice(@C, 0, 2)) {
my $nw = $G->get_attribute( 'weight', $u, $v );
$nw += $weight{ $u } if defined $weight{ $u };
# Relax the edge $u - $w.
if ( not defined $ow or $ow > $nw ) {
# Warn about detected negative cycles.
while (my ($u, $v) = splice(@E, 0, 2)) {
$weight{ $u } + $G->get_attribute( 'weight', $u, $v ) ) {
warn "SSSP_Bellman_Ford: negative cycle $u $v\n";
# Bail out if found negative cycles.
return undef if $negative;
# Otherwise return the SSSP graph.
return $G->_SSSP_construct( $s, \
%weight, \
%parent );
Returns the Single-source Shortest Paths (as a graph)
of the DAG $G starting from vertex $s.
my $SSSP = (ref $G)->new;
# Because by definition there can be no cycles
# we can freely explore each successor of each vertex.
foreach my $u ( $G->toposort ) {
foreach my $v ( $G->successors( $u ) ) {
my $nw = $G->get_attribute( 'weight', $u, $v );
$nw += $weight{ $u } if defined $weight{ $u };
# Relax the edge $u - $v.
if ( not defined $ow or $ow > $nw ) {
return $G->_SSSP_construct( $s, \
%weight, \
%parent );
$G->add_capacity_edge($u, $w, $v, $a)
Adds in the graph $G an edge from vertex $u to vertex $v
and the edge attribute 'capacity' set to $w.
my ($G, $u, $w, $v, $a) = @_;
$G->set_attribute('capacity', $u, $v, $w);
$G->add_capacity_edges($u1, $w1, $v1, $u2, $w2, $v2, ...)
Adds in the graph $G the capacity edges.
while (my ($u, $w, $v) = splice(@_, 0, 3)) {
$G->add_capacity_edge($u, $w, $v);
$G->add_capacity_path($v1, $w1, $v2, $w2, ..., $wnm1, $vn)
Adds in the graph $G the n edges defined by the path $v1 ... $vn
with the n-1 'capacity' attributes $w1 ... $wnm1
while (my ($w, $v) = splice(@_, 0, 2)) {
$G->add_capacity_edge($u, $w, $v);
=item Flow_Ford_Fulkerson
$F = $G->Flow_Ford_Fulkerson($S)
Returns the (maximal) flow network of the flow network $G,
parametrized by the state $S. The $G must have 'capacity'
attributes on its edges. $S->{ source } must contain the
source vertex and $S->{ sink } the sink vertex, and
most importantly $S->{ next_augmenting_path } must contain
an anonymous subroutine which takes $F and $S as arguments
and returns the next potential augmenting path.
Flow_Ford_Fulkerson will do the augmenting.
The result graph $F will have 'flow' and (residual) 'capacity'
sub Flow_Ford_Fulkerson
{
my $F = (ref $G)->new; # The flow network.
# Copy the edges and the capacities, zero the flows.
while (($u, $v) = splice(@E, 0, 2)) {
$F->set_attribute( 'capacity', $u, $v,
$G->get_attribute( 'capacity', $u, $v ) || 0 );
$F->set_attribute( 'flow', $u, $v, 0 );
# Walk the augmenting paths.
while ( my $ap = $S->{ next_augmenting_path
}->( $F, $S ) ) {
my @aps = @
$ap; # augmenting path segments
my $apr; # augmenting path residual capacity
my $psr; # path segment residual capacity
# Find the minimum capacity of the path.
for ( $u = shift @aps; @aps; $u = $v ) {
$psr = $F->get_attribute( 'capacity', $u, $v ) -
$F->get_attribute( 'flow', $u, $v );
if $psr >= 0 and ( not defined $apr or $psr < $apr );
if ( $apr > 0 ) { # Augment the path.
for ( @aps = @
$ap, $u = shift @aps; @aps; $u = $v ) {
$F->set_attribute( 'flow',
$F->get_attribute( 'flow', $u, $v ) +
$F = $G->Flow_Edmonds_Karp($source, $sink)
Return the maximal flow network of the graph $G built
using the Edmonds-Karp version of Ford-Fulkerson.
The input graph $G must have 'capacity' attributes on
its edges; resulting flow graph will have 'capacity' and 'flow'
my ( $G, $source, $sink ) = @_;
$S->{ source
} = $source;
$S->{ next_augmenting_path
} =
my $source = $S->{ source
};
# Initialize our "todo" heap.
unless ( exists $S->{ todo
} ) {
# The first element is a hash recording the vertices
# seen so far, the rest are the path from the source.
[ { $source => 1 }, $source ];
while ( @
{ $S->{ todo
} } ) {
# $ap: The next augmenting path.
my $ap = shift @
{ $S->{ todo
} };
my $sv = shift @
$ap; # The seen vertices.
my $v = $ap->[ -1 ]; # The last vertex of path.
foreach my $s ( $G->successors( $v ) ) {
unless ( exists $sv->{ $s } ) {
[ { %$sv, $s => 1 }, @
$ap, $s ];
return $G->Flow_Ford_Fulkerson( $S );
use overload
'eq' => \
&eq;
Return true if the graphs (actually, their string representations)
are identical. This means really identical: they must have identical
vertex names and identical edges between the vertices, and they must
be similarly directed. (Just isomorphism isn't enough.)
return ref $H ?
$G->stringify eq $H->stringify : $G->stringify eq $H;
Copyright 1999, O'Reilly & Associates.
This code is distributed under the same copyright terms as Perl itself.