Archive Ensembl HomeArchive Ensembl Home
Link.pm
Go to the documentation of this file.
00001 =head1 NAME
00002 
00003 Link - DESCRIPTION of Object
00004 
00005 =head1 SYNOPSIS
00006 
00007 =head1 DESCRIPTION
00008 
00009 Object oriented graph system which is based on Node and Link objects.  There is
00010 no 'graph' object, the graph is constructed out of Nodes and Links, and the
00011 graph is 'walked' from Node to Link to Node.  Can be used to represent any graph
00012 structure from DAGs (directed acyclic graph) to Trees to undirected cyclic Graphs.
00013 
00014 The system is fully connected so from any object in the graph one can 'walk' to
00015 any other.  Links contain pointers to the nodes on either side (called neighbors),
00016 and each Node contains a list of the links it is connected to.  
00017 Nodes also keep hashes of their neighbors for fast 'set theory' operations.  
00018 This graph system is used as the foundation for the Nested-set 
00019 (Compara::NestedSet) system for storing trees in the compara database.
00020 
00021 System has a simple API based on creating Nodes and then linking them together:
00022   my $node1 = new Bio::EnsEMBL::Compara::Graph::Node;
00023   my $node2 = new Bio::EnsEMBL::Compara::Graph::Node;
00024   new Bio::EnsEMBL::Compara::Graph::Link($node1, $node2, $distance_between);
00025 And to 'disconnect' nodes, one just breaks a link;
00026   my $link = $node1->link_for_neighbor($node2);
00027   $link->dealloc;
00028 Convenience methods to simplify this process
00029   $node1->create_link_to_node($node2, $distance_between);
00030   $node2->unlink_neighbor($node1);
00031   
00032 =head1 CONTACT
00033 
00034   Contact Jessica Severin on implemetation/design detail: jessica@ebi.ac.uk
00035   Contact Ewan Birney on EnsEMBL in general: birney@sanger.ac.uk
00036 
00037 =head1 APPENDIX
00038 
00039 The rest of the documentation details each of the object methods. Internal methods are usually preceded with a _
00040 
00041 =cut
00042 
00043 
00044 
00045 package Bio::EnsEMBL::Compara::Graph::Link;
00046 
00047 use strict;
00048 use Bio::EnsEMBL::Utils::Exception;
00049 use Bio::EnsEMBL::Utils::Argument;
00050 use Bio::EnsEMBL::Compara::Graph::CGObject;
00051 
00052 our @ISA = qw(Bio::EnsEMBL::Compara::Graph::CGObject);
00053 
00054 #################################################
00055 # Factory methods
00056 #################################################
00057 
00058 =head2 new
00059 
00060   Arg [1]    : <Bio::EnsEMBL::Compara::Graph::Node> node1
00061   Arg [2]    : <Bio::EnsEMBL::Compara::Graph::Node> node2
00062   Arg [3]    : (opt.) <float> length of link
00063   Example    : $link = new Bio::EnsEMBL::Compara::Graph::Link($node1, $node2);
00064   Description: creates new link between nodes
00065   Returntype : Bio::EnsEMBL::Compara::Graph::Link
00066   Exceptions : none
00067 
00068 =cut
00069 
00070 sub new {
00071   my $class = shift;
00072   my $node1 = shift;
00073   my $node2 = shift;
00074   my $dist = shift;
00075 
00076   throw("arg1 must be a [Bio::EnsEMBL::Compara::Graph::Node] not a [$node1]")
00077         unless(defined($node1) and $node1->isa('Bio::EnsEMBL::Compara::Graph::Node'));
00078   throw("arg2 must be a [Bio::EnsEMBL::Compara::Graph::Node] not a [$node2]")
00079         unless(defined($node2) and $node2->isa('Bio::EnsEMBL::Compara::Graph::Node'));
00080 
00081   my $self = $class->SUPER::new;
00082   bless $self, "Bio::EnsEMBL::Compara::Graph::Link";
00083 
00084   $self->{'_link_node1'} = $node1;
00085   $self->{'_link_node2'} = $node2;
00086   
00087   $node1->_add_neighbor_link_to_hash($node2, $self);
00088   $node2->_add_neighbor_link_to_hash($node1, $self);
00089   
00090   $self->distance_between($dist) if(defined($dist));
00091   return $self;
00092 }
00093 
00094 
00095 sub dealloc {
00096   my $self = shift;
00097   
00098   $self->{'_link_node1'}->_unlink_node_in_hash($self->{'_link_node2'});
00099   $self->{'_link_node2'}->_unlink_node_in_hash($self->{'_link_node1'});
00100 
00101   $self->{'_link_node1'} = undef;
00102   $self->{'_link_node2'} = undef;
00103   
00104   #printf("DEALLOC link refcount:%d ", $self->refcount);
00105 }
00106 
00107 
00108 # copy system is based that the nodes make the copies
00109 # and the link just links (retains) 
00110 sub copy {
00111   my $self = shift;
00112   
00113   my ($node1, $node2) = $self->get_nodes;
00114   my $mycopy = new Bio::EnsEMBL::Compara::Graph::Link($node1, $node2);
00115   $mycopy->distance_between($self->distance_between);
00116 
00117   return $mycopy;
00118 }
00119 
00120 =head2 get_nodes
00121 
00122   Example    : ($node1, $node2) = $link->get_nodes;
00123   Description: returns the nodes as an unordered list
00124   Returntype : undef
00125   Exceptions : none
00126 
00127 =cut
00128 
00129 sub get_nodes {
00130   my $self = shift;
00131   return ($self->{'_link_node1'}, $self->{'_link_node2'});
00132 }
00133 
00134 =head2 get_neighbor
00135 
00136   Example    : $node2 = $link->get_neighbor($node1);
00137   Description: returns the other node in a link given a node.  return undef if $node1 
00138                is not part of the link.
00139   Returntype : Bio::EnsEMBL::Compara::Graph::Node or undef
00140   Exceptions : none
00141 
00142 =cut
00143 
00144 sub get_neighbor {
00145   my $self = shift;
00146   my $node = shift;
00147   
00148   return $self->{'_link_node2'} if($node eq $self->{'_link_node1'});
00149   return $self->{'_link_node1'} if($node eq $self->{'_link_node2'});
00150   return undef;
00151 }
00152 
00153 =head2 distance_between
00154 
00155   Arg [1]    : (opt.) <int or double> distance
00156   Example    : my $dist = $link->distance_between();
00157   Example    : $link->distance_between(1.618);
00158   Description: Getter/Setter for the distance between the nodes
00159   Returntype : <int or double> distance
00160   Exceptions : none
00161   Caller     : general
00162 
00163 =cut
00164 
00165 sub distance_between {
00166   my $self = shift;
00167   $self->{'_distance_between'} = shift if(@_);
00168   $self->{'_distance_between'} = 0.0 unless(defined($self->{'_distance_between'}));
00169   return $self->{'_distance_between'};
00170 }
00171 
00172 sub equals {
00173   my $self = shift;
00174   my $other = shift;
00175 #  throw("arg must be a [Bio::EnsEMBL::Compara::Graph::Link] not a [$other]")
00176 #        unless($other and $other->isa('Bio::EnsEMBL::Compara::Graph::Link')); # BEWARE speed up change uncommented
00177   return 1 if($self eq $other);
00178   return 0;
00179 }
00180 
00181 sub print_link {
00182   my $self  = shift;
00183   printf("link(%s): (%s)-- %1.5f --(%s)\n", 
00184       $self->obj_id, 
00185       $self->{'_link_node1'}->node_id,
00186       $self->distance_between,
00187       $self->{'_link_node2'}->node_id,
00188     );
00189 }
00190 
00191 
00192 1;
00193