Make transposition data go into pool arrays
Tara L Andrews [Tue, 19 Apr 2011 18:45:21 +0000 (20:45 +0200)]
lib/Traditions/Graph.pm
lib/Traditions/Parser/GraphML.pm
t/graph.t

index 558de2f..2c9efe8 100644 (file)
@@ -119,9 +119,13 @@ sub edge {
     return $self->{'graph'}->edge( @_ );
 }
 
+# Not only adds the node, but also initializes internal data
+# about the node.
 sub add_node {
     my $self = shift;
-    return $self->{'graph'}->add_node( @_ );
+    my $node = $self->{'graph'}->add_node( @_ );
+    $self->{'identical_nodes'}->{ $node->name() } = [ $node->name() ];
+    return $node;
 }
 
 sub add_edge {
@@ -131,6 +135,26 @@ sub add_edge {
 
 sub del_node {
     my $self = shift;
+    my $node = $_[0];
+
+    # Delete this node out of any relevant transposition pool.
+    if( ref $node eq 'Graph::Easy::Node' ) {
+       $node = $node->name();
+    }
+    my @ident = $self->identical_nodes( $node );
+    if( @ident ) {
+       # Get the pool.
+       my $pool = $self->{'identical_nodes'}->{ $ident[0] };
+       foreach my $i ( 0 .. scalar(@$pool)-1 ) {
+           if( $pool->[$i] eq $node ) {
+               splice( @$pool, $i, 1 );
+               last;
+           }
+       }
+    }
+    delete $self->{'identical_nodes'}->{ $node };
+
+    # Now delete the node.
     return $self->{'graph'}->del_node( @_ );
 }
 
@@ -161,14 +185,37 @@ sub start {
     my $self = shift;
     my( $new_start ) = @_;
     if( $new_start ) {
+       # Fix the node transposition data
+       delete $self->{'identical_nodes'}->{ $new_start->name() };
+       $self->{'identical_nodes'}->{'#START#'} = [ '#START#' ];
        $self->{'graph'}->rename_node( $new_start, '#START#' );
     }
     return $self->{'graph'}->node('#START#');
 }
 
-sub set_identical_nodes {
-    my( $self, $node_hash ) = @_;
-    $self->{'identical_nodes'} = $node_hash;
+# Record that nodes A and B are really the same (transposed) node.
+# We do this by maintaining some pools of transposed nodes, and
+# we have a lookup hash so that each member of that 
+sub set_identical_node {
+    my( $self, $node, $same_node ) = @_;
+    my $pool = $self->{'identical_nodes'}->{ $node };
+    my $same_pool = $self->{'identical_nodes'}->{ $same_node };
+    my %poolhash;
+    foreach ( @$pool ) {
+       $poolhash{$_} = 1;
+    }
+    foreach( @$same_pool ) {
+       push( @$pool, $_ ) unless $poolhash{$_};
+    }
+
+    $self->{'identical_nodes'}->{ $same_node } = $pool;
+}
+
+sub identical_nodes {
+    my( $self, $node ) = @_;
+    my @others = grep { $_ !~ /^$node$/ } 
+        @{$self->{'identical_nodes'}->{ $node }};
+    return @others;
 }
 
 sub next_word {
@@ -420,13 +467,6 @@ sub colocated_nodes {
     return $self->{'positions'}->colocated_nodes( @_ );
 }
 
-sub identical_nodes {
-    my( $self, $node ) = @_;
-    return undef unless exists $self->{'identical_nodes'} &&
-       exists $self->{'identical_nodes'}->{$node};
-    return $self->{'identical_nodes'}->{$node};
-}
-
 sub text_of_node {
     my( $self, $node_id ) = @_;
     # This is the label of the given node.
index 3656eb9..4662296 100644 (file)
@@ -77,16 +77,15 @@ sub parse {
     my %node_id = reverse %node_name;
 
     ## Record the nodes that are marked as transposed.
-    my $id_xpath = '//g:node[g:data[@key="' . $nodedata{'identity'} . '"]]';
-    my $transposed_nodes = $xpc->find( $id_xpath );
-    my $identical_nodes;
-    foreach my $tn ( @$transposed_nodes ) {
-        $identical_nodes->{ $node_name{ $tn->getAttribute('id') }} = 
-            $node_name{ $xpc->findvalue( './g:data[@key="' 
-                                        . $nodedata{'identity'} 
-                                        . '"]/text()', $tn ) };
+    my $tr_xpath = '//g:node[g:data[@key="' . $nodedata{'identity'} . '"]]';
+    my $transposition_nodes = $xpc->find( $tr_xpath );
+    foreach my $tn ( @$transposition_nodes ) {
+       my $id_xpath = sprintf( './g:data[@key="%s"]/text()', 
+                               $nodedata{'identity'} );
+       $graph->set_identical_node( $node_name{ $tn->getAttribute( 'id' ) },
+                                   $node_name{ $xpc->findvalue( $id_xpath, 
+                                                                $tn ) } );
     }
-    $graph->set_identical_nodes( $identical_nodes );
 
 
     # Find the beginning and end nodes of the graph.  The beginning node
index a60353d..91f9311 100644 (file)
--- a/t/graph.t
+++ b/t/graph.t
@@ -76,13 +76,18 @@ is( $graph->text_for_witness( "B" ), $wit_b, "Correct path for witness B" );
 is( $graph->text_for_witness( "C" ), $wit_c, "Correct path for witness C" );
 
 # Test the transposition identifiers
-my $transposed_nodes = { 2 => 9,
-                        9 => 2,
-                        14 => 18,
-                        15 => 17,
-                        17 => 15,
-                        18 => 14
+my $transposition_pools = [ [ 2, 9 ], [ 14, 18 ], [ 15, 17 ] ];
+my $transposed_nodes = { 2 => $transposition_pools->[0],
+                        9 => $transposition_pools->[0],
+                        14 => $transposition_pools->[1],
+                        15 => $transposition_pools->[2],
+                        17 => $transposition_pools->[2],
+                        18 => $transposition_pools->[1],
 };
+foreach my $n ( $graph->nodes() ) {
+    $transposed_nodes->{ $n->name() } = [ $n->name() ]
+       unless exists $transposed_nodes->{ $n->name() };
+}
 is_deeply( $graph->{'identical_nodes'}, $transposed_nodes, "Found the right transpositions" );
 
 # Test turning on a node