3 See the NOTICE file distributed with
this work
for additional information
4 regarding copyright ownership.
6 Licensed under the Apache License, Version 2.0 (the
"License");
7 you may not use
this file except in compliance with the License.
8 You may obtain a copy of the License at
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an
"AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License
for the specific language governing permissions and
16 limitations under the License.
23 Please email comments or questions to the
public Ensembl
24 developers list at <http:
26 Questions may also be sent to the Ensembl help desk at
37 my $registry =
"Bio::EnsEMBL::Registry";
38 my $archiveStableIdAdaptor =
39 $registry->get_adaptor(
'human',
'core',
'ArchiveStableId' );
41 my $stable_id =
'ENSG00000068990';
43 $archiveStableIdAdaptor->fetch_history_tree_by_stable_id(
'ENSG01');
45 print
"Unique stable IDs in this tree:\n";
46 print join(
", ", @{ $history->get_unique_stable_ids } ),
"\n";
48 print
"\nReleases in this tree:\n";
49 print join(
", ", @{ $history->get_release_display_names } ),
"\n";
51 print
"\nCoordinates of nodes in the tree:\n\n";
52 foreach my $a ( @{ $history->get_all_ArchiveStableIds } ) {
53 print
" Stable ID: " . $a->stable_id .
"." . $a->version .
"\n";
57 . $a->db_name .
")\n";
59 . join(
', ', @{ $history->coords_by_ArchiveStableId($a) } )
65 This
object represents a stable ID history tree graph.
67 The graph is implemented as a collection of nodes (ArchiveStableId
68 objects) and links (StableIdEvent objects) which have positions
69 on an (x,y) grid. The x axis is used
for releases, the y axis
for
70 stable_ids. The idea is to create a plot similar to
this (the numbers
71 shown on the nodes are the stable ID versions):
73 ENSG001 1-------------- 2--
77 ENSG002 1-------2----------
82 would be (note that coordinates are zero-based):
86 ENSG003.1 (release 41) (3, 1)
87 ENSG003.1 (release 42) (4, 1)
91 The tree will only contain those nodes which had a change in the stable
92 ID version. Therefore, in the above example, in release 39 ENSG001 was
93 present and had version 1 (but will not be drawn there, to unclutter the
96 The grid positions will be calculated by the API and will
try to
97 untangle the tree (i.e.
try to avoid overlapping lines).
103 add_ArchiveStableIds_for_events
104 remove_ArchiveStableId
105 flush_ArchiveStableIds
109 get_all_ArchiveStableIds
110 get_all_StableIdEvents
111 get_latest_StableIdEvent
112 get_release_display_names
114 get_unique_stable_ids
116 coords_by_ArchiveStableId
125 =head1 RELATED MODULES
133 package Bio::EnsEMBL::StableIdHistoryTree;
137 no warnings
'uninitialized';
146 Arg [CURRENT_DBNAME] : (optional) name of current db
147 Arg [CURRENT_RELEASE] : (optional) current release number
148 Arg [CURRENT_ASSEMBLY] : (optional) current assembly name
150 Description :
object constructor
161 my $class = ref($caller) || $caller;
166 my ($current_dbname, $current_release, $current_assembly) =
167 rearrange([qw( CURRENT_DBNAME CURRENT_RELEASE CURRENT_ASSEMBLY )], @_ );
170 $self->{
'current_dbname'} = $current_dbname;
171 $self->{
'current_release'} = $current_release;
172 $self->{
'current_assembly'} = $current_assembly;
178 =head2 add_ArchiveStableIds
181 The ArchiveStableIds to add to the the history tree
182 Example : my $archive_id = $archiveStableIdAdaptor->fetch_by_stable_id(
184 $history->add_ArchiveStableId($archive_id);
185 Description : Adds ArchiveStableIds (nodes) to the history tree. No
186 calculation of grid coordinates is done at this point, you need
187 to initiate this manually with calculate_coords().
188 ArchiveStableIds are only added once for each release (to avoid
191 Exceptions : thrown on invalid or missing argument
192 Caller : Bio::EnsEMBL::DBSQL::ArchiveStableIdAdaptor::fetch_history_by_stable_id, general
198 sub add_ArchiveStableIds {
199 my ($self, @archive_ids) = @_;
201 throw("You must provide one or more Bio::EnsEMBL::ArchiveStableIds to add.")
202 unless (@archive_ids);
204 foreach my $archive_id (@archive_ids) {
205 throw("Bio::EnsEMBL::ArchiveStableId object expected.")
206 unless (ref($archive_id) &&
209 $self->{'nodes
'}->{$self->_node_id($archive_id)} = $archive_id;
214 =head2 add_ArchiveStableIds_for_events
216 Example : my $history = Bio::EnsEMBL::StableIdHistoryTree->new;
217 $history->add_StableIdEvents($event1, $event2);
218 $history->add_ArchiveStableIds_for_events;
219 Description : Convenience method that adds all ArchiveStableIds for all
220 StableIdEvents attached to this object to the tree.
223 Caller : Bio::EnsEMBL::DBSQL::ArchiveStableIdAdaptor::fetch_history_by_stable_id, general
229 sub add_ArchiveStableIds_for_events {
232 foreach my $event (@{ $self->get_all_StableIdEvents }) {
233 if ($event->old_ArchiveStableId) {
234 $self->add_ArchiveStableIds($event->old_ArchiveStableId);
236 if ($event->new_ArchiveStableId) {
237 $self->add_ArchiveStableIds($event->new_ArchiveStableId);
243 =head2 remove_ArchiveStableId
245 Arg[1] : Bio::EnsEMBL::ArchiveStableId $archive_id
246 the ArchiveStableId to remove from the tree
247 Example : $history->remove_ArchiveStableId($archive_id);
248 Description : Removes an ArchiveStableId from the tree.
250 Exceptions : thrown on missing or invalid argument
251 Caller : Bio::EnsEMBL::DBSQL::ArchiveStableIdAdaptor::fetch_history_by_stable_id, general
257 sub remove_ArchiveStableId {
258 my ($self, $archive_id) = @_;
260 throw("Bio::EnsEMBL::ArchiveStableId object expected.")
261 unless ($archive_id && ref($archive_id) &&
264 my %nodes = %{ $self->{'nodes
'} };
265 delete $nodes{$self->_node_id($archive_id)};
266 $self->{'nodes
'} = \%nodes;
270 =head2 flush_ArchiveStableIds
272 Example : $history->flush_ArchiveStableIds;
273 Description : Remove all ArchiveStableIds from the tree.
282 sub flush_ArchiveStableIds {
284 $self->{'nodes
'} = undef;
289 # generate a unique node identifier
292 my ($self, $archive_id) = @_;
293 return $archive_id->stable_id . ':
' . $archive_id->db_name;
297 =head2 add_StableIdEvents
299 Arg[1..n] : Bio::EnsEMBL::StableIdEvent's @events
300 The StableIdEvents to add to the the history tree
301 Example : $history->add_StableIdEvents($event);
302 Description : Adds StableIdEvents (links) to the history tree. Note that
303 ArchiveStableIds attached to the StableIdEvent aren
't added to
304 the tree automatically, you'll need to call
305 add_ArchiveStableIds_for_events later.
307 Exceptions : thrown on invalid or missing argument
308 Caller : Bio::EnsEMBL::DBSQL::ArchiveStableIdAdaptor::fetch_history_by_stable_id, general
314 sub add_StableIdEvents {
315 my ($self, @events) = @_;
317 throw(
"You must provide one or more Bio::EnsEMBL::StableIdsEvents to add.")
320 foreach my $event (@events) {
321 throw(
"Bio::EnsEMBL::StableIdEvent object expected.")
322 unless ($event->isa(
'Bio::EnsEMBL::StableIdEvent'));
324 $self->{
'links'}->{$self->_link_id($event)} = $event;
329 =head2 remove_StableIdEvent
332 the StableIdEvent to remove from the tree
333 Example : $history->remove_StableIdEvent($event);
334 Description : Removes a StableIdEvent from the tree.
336 Exceptions : thrown on missing or invalid arguments
337 Caller : Bio::EnsEMBL::DBSQL::ArchiveStableIdAdaptor::fetch_history_by_stable_id, general
343 sub remove_StableIdEvent {
344 my ($self, $event) = @_;
346 throw(
"Bio::EnsEMBL::StableIdEvent object expected.") unless
347 ($event && ref($event) && $event->isa(
'Bio::EnsEMBL::StableIdEvent'));
349 my %links = %{ $self->{
'links'} };
350 delete $links{$self->_link_id($event)};
351 $self->{
'links'} = \%links;
355 =head2 flush_StableIdEvents
357 Example : $history->flush_StableIdEvents;
358 Description : Removes all StableIdEvents from the tree.
367 sub flush_StableIdEvents {
369 $self->{
'links'} = undef;
374 # generate a unique link identifier
377 my ($self, $event) = @_;
379 my ($old_id, $old_db_name, $new_id, $new_db_name);
380 if ($event->old_ArchiveStableId) {
381 $old_id = $event->old_ArchiveStableId->stable_id;
382 $old_db_name = $event->old_ArchiveStableId->db_name;
384 if ($event->new_ArchiveStableId) {
385 $new_id = $event->new_ArchiveStableId->stable_id;
386 $new_db_name = $event->new_ArchiveStableId->db_name;
389 return join(
':', $old_id, $old_db_name, $new_id, $new_db_name);
393 =head2 get_all_ArchiveStableIds
395 Example :
foreach my $arch_id (@{ $history->get_all_ArchiveStableIds }) {
396 print $arch_id->stable_id,
'.', $arch_id->version,
"\n";
398 Description : Gets all ArchiveStableIds (nodes) in
this tree.
407 sub get_all_ArchiveStableIds {
409 return [ values %{ $self->{
'nodes'} } ];
413 =head2 get_all_current_ArchiveStableIds
415 Example :
foreach my $arch_id (@{ $history->get_all_current_ArchiveStableIds }) {
416 print $arch_id->
stable_id,
'.', $arch_id->version,
"\n";
418 Description : Convenience method to get all current ArchiveStableIds in
this
421 Note that no lazy loading of
"current" status is done at that
422 stage; as
long as you retrieve your StableIdHistoryTree
object
423 from ArchiveStableIdAdaptor, you
'll get the right answer. In
424 other use cases, if you want to make sure you really get all
425 current stable IDs, loop over the result of
426 get_all_ArchiveStableIds() and call
427 ArchiveStableId->current_version() on all of them.
428 Return type : Arrayref of Bio::EnsEMBL::ArchiveStableId objects
436 sub get_all_current_ArchiveStableIds {
441 foreach my $arch_id (@{ $self->get_all_ArchiveStableIds }) {
442 push @current, $arch_id if ($arch_id->is_current);
449 =head2 get_all_StableIdEvents
451 Example : foreach my $event (@{ $history->get_all_StableIdsEvents }) {
452 print "Old stable ID: ",
453 ($event->get_attribute('old
', 'stable_id
') or 'none
'), "\n";
454 print "New stable ID: ",
455 ($event->get_attribute('new', 'stable_id
') or 'none
'), "\n";
456 print "Mapping score: ", $event->score, "\n";
458 Description : Gets all StableIdsEvents (links) in this tree.
459 Return type : Arrayref of Bio::EnsEMBL::StableIdEvent objects
467 sub get_all_StableIdEvents {
469 return [ values %{ $self->{'links
'} } ];
473 =head2 get_latest_StableIdEvent
475 Arg[1] : Bio::EnsEMBL::ArchiveStableId $arch_id - the stable ID to get
477 Example : my $arch_id = Bio::EnsEMBL::ArchiveStableId->new(
478 -stable_id => 'ENSG00001
'
480 my $event = $history->get_latest_Event($arch_id);
481 Description : Returns the latest StableIdEvent found in the tree where a given
482 stable ID is the new stable ID. If more than one is found (e.g.
483 in a merge scenario in the latest mapping), preference is given
485 Return type : Bio::EnsEMBL::StableIdEvent
486 Exceptions : thrown on missing or wrong argument
487 Caller : Bio::EnsEMBL::DBSQL::ArchiveStableIdAdaptor::add_all_current_to_history, general
493 sub get_latest_StableIdEvent {
498 throw("Need a Bio::EnsEMBL::ArchiveStableId.");
501 my @all_events = @{ $self->get_all_StableIdEvents };
502 my @self_events = ();
504 while (my $event = shift(@all_events)) {
505 if ($event->new_ArchiveStableId and
506 $event->new_ArchiveStableId->stable_id eq $arch_id->stable_id) {
507 push @self_events, $event;
511 my @sorted = sort { $b->new_ArchiveStableId->release <=>
512 $a->new_ArchiveStableId->release } @self_events;
514 # give priority to self events
516 while ($latest = shift @sorted) {
517 last if (($latest->old_ArchiveStableId and
518 $latest->old_ArchiveStableId->stable_id eq $arch_id->stable_id)
519 or !$latest->old_ArchiveStableId);
526 =head2 get_release_display_names
528 Example : print "Unique release display_names in this tree:\n"
529 foreach my $name (@{ $history->get_release_display_names }) {
532 Description : Returns a chronologically sorted list of unique release
533 display_names in this tree.
535 This method can be used to determine the number of columns when
536 plotting the history tree.
537 Return type : Arrayref of strings.
545 sub get_release_display_names {
548 my @display_names = map { $_->[1] } @{ $self->_sort_releases };
550 return \@display_names;
554 =head2 get_release_db_names
556 Example : print "Unique release db_names in this tree:\n"
557 foreach my $name (@{ $history->get_release_db_names }) {
560 Description : Returns a chronologically sorted list of unique release
561 db_names in this tree.
562 Return type : Arrayref of strings.
570 sub get_release_db_names {
573 my @db_names = map { $_->[0] } @{ $self->_sort_releases };
580 # Create a chronologically sorted list of releases.
582 # Return type : Arrayref of arrayrefs (db_name, release)
587 unless ($self->{'sorted_tree
'}->{'releases
'}) {
591 foreach my $archive_id (@{ $self->get_all_ArchiveStableIds }) {
592 $unique{join(':
', $archive_id->db_name, $archive_id->release)} = 1;
595 # sort releases by release number, then db_name; this should get them into
596 # chronological order
597 my @releases = sort { $a->[1] <=> $b->[1] || $a->[0] cmp $b->[0] }
598 map { [ split(/:/, $_) ] } keys(%unique);
600 $self->{'sorted_tree
'}->{'releases
'} = \@releases;
604 return $self->{'sorted_tree
'}->{'releases
'};
608 =head2 get_unique_stable_ids
610 Example : print "Unique stable IDs in this tree:\n"
611 foreach my $id (@{ $history->get_unique_stable_ids }) {
614 Description : Returns a list of unique stable IDs in this tree. Version is not
615 taken into account here. This method can be used to determine
616 the number of rows when plotting the history with each stable ID
619 Sort algorithm will depend on what was chosen when the sorted
620 tree was generated. This ranges from a simple alphanumeric sort
621 to algorithms trying to untangle the history tree. If no
622 pre-sorted data is found, an alphanumerically sorted list will
623 be returned by default.
624 Return type : Arrayref of strings.
632 sub get_unique_stable_ids {
635 unless ($self->{'sorted_tree
'}->{'stable_ids
'}) {
636 $self->{'sorted_tree
'}->{'stable_ids
'} = $self->_sort_stable_ids;
639 return $self->{'sorted_tree
'}->{'stable_ids
'};
644 # Returns a list of stable IDs in this history tree, sorted alphabetically.
645 # This is the simplest sort function used and doesn't
try to untangle the tree.
647 # Return type : Arrayref
649 sub _sort_stable_ids {
651 my %unique =
map { $_->stable_id => 1 } @{ $self->get_all_ArchiveStableIds };
652 return [sort keys %unique];
658 Arg [1] : (optional) Float $time_limit
659 Optimise tree normally runs until it hits a minimised state
660 but
this can take a very
long time. Therefore you can
661 opt to bail out of the optimisation early. Specify the
662 time in seconds. Floating point values are supported should you
663 require sub-second limits
664 Example : $history->optimise_tree;
665 Description : This method sorts the history tree so that the number of
666 overlapping branches is minimised (thus
"untangling" the tree).
668 It uses a clustering algorithm
for this which iteratively moves
669 the nodes with the largest vertical distance next to each other
670 and looking
for a mininum in total branch length. This might not
671 produce the overall optimum but usually converges on a local
672 optimum very quickly.
675 Caller : calculate_coords
683 my $time_limit = shift;
685 # get all non-self events
687 foreach my $event (@{ $self->get_all_StableIdEvents }) {
688 next unless ($event->old_ArchiveStableId and $event->new_ArchiveStableId);
689 my $old_id = $event->old_ArchiveStableId->stable_id;
690 my $new_id = $event->new_ArchiveStableId->stable_id;
691 push @links, [$old_id, $new_id]
if ($old_id ne $new_id);
694 # get initial list of sorted unique stable IDs and put them into a position
697 my %pos =
map { $_ => $i++ } @{ $self->_sort_stable_ids };
700 my $successive_fails = 0;
704 # for debug purposes:
705 # find the number of permutations for the given number of stable IDs
706 my $fact = $self->_factorial(scalar(keys %pos));
708 my $starting_time = Time::HiRes::time();
711 while ($successive_fails < 100) {
713 if(defined $time_limit) {
714 my $current_time = Time::HiRes::time();
715 my $diff = $current_time - $starting_time;
716 last OPT
if $diff > $time_limit;
719 # sort links by vertical distance
721 $self->_sort_links(\@links, \%pos);
723 # loop over sorted links
725 foreach my $link (@links) {
727 #warn " trying ".join('-', @$link)."\n";
731 # remember last sort order
734 #my $this_order = join(':', sort { $pos{$a} <=> $pos{$b} } keys %pos);
735 #warn " before $this_order\n";
737 # try both to move bottom node next to top node's current position and
738 # top node next to bottom node's position - one of the methods might give
741 foreach my $direction (qw(up down)) {
743 # move the nodes next to each other
744 $self->_move_nodes($link, \%pos, $direction);
746 # next if we've seen this sort order before
747 my $new_order = join(
':', sort { $pos{$a} <=> $pos{$b} } keys %pos);
748 #warn " after ($direction) $new_order\n";
749 if ($seen{$new_order}) {
754 $seen{$new_order} = 1;
756 # calculate total link length for this sort order
757 my $total_length = $self->_total_link_length(\@links, \%pos);
759 if (!$opt_length or $total_length < $opt_length) {
760 #warn " better ($total_length/$opt_length)\n";
761 $opt_length = $total_length;
762 $successive_fails = 0;
765 #warn " worse ($total_length/$opt_length)\n";
777 #warn "Needed $k tries (of $fact) to find optimal tree.\n";
779 my @best = sort { $pos{$a} <=> $pos{$b} } keys %pos;
780 $self->{
'sorted_tree'}->{
'stable_ids'} = \@best;
785 # find the number of permutations for a give array size.
786 # used for debugging code (compare implemented algorithm to looping over all
787 # possible permutations).
792 $s *= $n--
while $n > 0;
798 # sort links by vertical distance
801 my ($self, $links, $pos) = @_;
805 foreach my $link (@$links) {
806 my $dist = $pos->{$link->[0]} - $pos->{$link->[1]};
807 $dist = -$dist
if ($dist < 0);
808 push @lookup, [$dist, $link];
809 #warn " $dist ".join(' ', @$link)."\n";
812 @$links =
map { $_->[1] } sort { $b->[0] <=> $a->[0] } @lookup;
817 # make two nodes adjacent by moving the second node next to the first node
818 # all other node coordinates are adjusted accordingly
821 my ($self, $link, $pos, $direction) = @_;
823 my $first_pos = $pos->{$link->[0]};
824 my $second_pos = $pos->{$link->[1]};
826 # swap positions if necessary
827 if ($first_pos > $second_pos) {
828 my $tmp = $second_pos;
829 $second_pos = $first_pos;
832 #warn " $first_pos:$second_pos\n";
834 foreach my $p (keys %$pos) {
836 my $val = $pos->{$p};
839 if ($direction eq
'up') {
840 if ($val > $first_pos and $val < $second_pos) {
842 } elsif ($val == $second_pos) {
843 $val = $first_pos + 1;
846 if ($val > $first_pos and $val < $second_pos) {
848 } elsif ($val == $first_pos) {
849 $val = $second_pos - 1;
861 # calculate the total link (vertical distance) length based on this sort order
863 sub _total_link_length {
864 my ($self, $links, $pos) = @_;
868 foreach my $link (@$links) {
869 my $length = $pos->{$link->[0]} - $pos->{$link->[1]};
870 $length = -$length
if ($length < 0);
871 $total_length += $length;
874 return $total_length;
878 =head2 coords_by_ArchiveStableId
881 The ArchiveStableId to get tree grid coordinates
for
882 Example : my ($x, $y) =
883 @{ $history->coords_by_ArchiveStableId($archive_id) };
884 print $archive_id->
stable_id,
" coords: $x, $y\n";
885 Description : Returns the coordinates of an ArchiveStableId in the history
886 tree grid. If the ArchiveStableId isn
't found in this tree, an
887 empty list is returned.
889 Coordinates are zero-based (i.e. the top leftmost element in
890 the grid has coordinates [0, 0], not [1, 1]). This is to
891 facilitate using them to create a matrix as a two-dimensional
893 Return type : Arrayref (x coordinate, y coordinate)
894 Exceptions : thrown on wrong argument type
901 sub coords_by_ArchiveStableId {
902 my ($self, $archive_id) = @_;
904 throw("Bio::EnsEMBL::ArchiveStableId object expected.")
905 unless ($archive_id and ref($archive_id) and
908 return $self->{'sorted_tree
'}->{'coords
'}->{$self->_node_id($archive_id)}
913 =head2 calculate_coords
915 Arg [1] : (optional) Float $time_limit
916 Optimise tree normally runs until it hits a minimised state
917 but this can take a very long time. Therefore you can
918 opt to bail out of the optimisation early. Specify the
919 time in seconds. Floating point values are supported should you
920 require sub-second limits
921 Example : $history->calculate_coords;
922 Description : Pre-calculates the grid coordinates of all nodes in the tree.
925 Caller : ArchiveStableIdAdaptor::fetch_history_by_stable_id
931 sub calculate_coords {
933 my $time_limit = shift;
935 # reset any previous tree cordinate calculations
938 # the "master" information for the sorted tree is stored as the sorted lists
939 # of releases (x) and stable IDs (y). Sort them now.
940 my $db_names = $self->get_release_db_names;
942 # untangle tree by sorting stable IDs appropriately
943 $self->optimise_tree($time_limit);
944 my $stable_ids = $self->get_unique_stable_ids;
946 # for performance reasons, additionally store coordinates in a lookup hash
947 foreach my $archive_id (@{ $self->get_all_ArchiveStableIds }) {
949 # coordinates are positions in the sorted lists
950 my $x = $self->_index_of($archive_id->db_name, $db_names);
951 my $y = $self->_index_of($archive_id->stable_id, $stable_ids);
953 $self->{'sorted_tree
'}->{'coords
'}->{$self->_node_id($archive_id)} =
959 # Description : Returns the index of an element in an array
960 # Example : my @array = (a, b, c);
961 # my $i = _index_of('b
', \@array); # will return 1
962 # Return type : Int (or undef if element is not found in array)
965 my ($self, $element, $arrayref) = @_;
967 throw("Expecting arrayref argument.") unless (ref($arrayref) eq 'ARRAY
');
969 my @array = @$arrayref;
971 while (my $e = pop(@array)) {
972 return scalar(@array) if ($e eq $element);
979 =head2 consolidate_tree
981 Example : $history->consolidate_tree;
982 Description : Consolidate the history tree. This means removing nodes where
983 there wasn't a change and bridging gaps in the history. The end
984 result will be a sparse tree which only contains the necessary
988 Caller : ArchiveStableIdAdaptor->fetch_history_tree_by_stable_id
994 sub consolidate_tree {
998 # get all self-events and creations/deletions and sort them (by stable ID and
1003 foreach my $event (@{ $self->get_all_StableIdEvents }) {
1005 my $old_id = $event->old_ArchiveStableId;
1006 my $new_id = $event->new_ArchiveStableId;
1008 if (!$old_id or !$new_id or ($old_id->stable_id eq $new_id->stable_id)) {
1010 push @event_lookup, [$old_id->stable_id, $old_id->release,
1011 $old_id->db_name, $event];
1013 push @event_lookup, [$new_id->stable_id, $new_id->release - 1,
1014 $new_id->db_name, $event];
1019 my @self_events =
map { $_->[3] }
1020 sort { $a->[0] cmp $b->[0] || $a->[1] <=> $b->[1] || $a->[2] cmp $b->[2] }
1026 my $last = shift(@self_events);
1028 while (my $event = shift(@self_events)) {
1030 my $lo = $last->old_ArchiveStableId;
1031 my $ln = $last->new_ArchiveStableId;
1032 my $eo = $event->old_ArchiveStableId;
1033 my $en = $event->new_ArchiveStableId;
1035 if ($lo and $eo and $en and $lo->stable_id eq $eo->stable_id
1036 and $lo->version eq $eo->version) {
1038 # this removes redundant nodes and connects the remaining nodes:
1040 # o--o--o -> o-----o
1043 #warn 'A: '.$last->ident_string.' | '.$event->ident_string."\n";
1045 $self->remove_StableIdEvent($last);
1046 $self->remove_StableIdEvent($event);
1048 $event->old_ArchiveStableId($lo);
1050 $self->add_StableIdEvents($event);
1052 } elsif ($ln and $eo and $ln->db_name ne $eo->db_name
1053 and $ln->stable_id eq $eo->stable_id and $ln->version eq $eo->version) {
1055 # try to brigde gaps
1059 # o--o o--o -> o--o-----o
1065 #warn 'X: '.$last->ident_string.' | '.$event->ident_string."\n";
1067 $self->remove_StableIdEvent($event);
1068 $event->old_ArchiveStableId($ln);
1069 $self->add_StableIdEvents($event);
1073 # there's a deletion event, deal with it differently
1075 if ($lo->version eq $ln->version) {
1080 #warn 'Y: '.$last->ident_string.' | '.$event->ident_string."\n";
1082 $self->remove_StableIdEvent($last);
1083 $last->new_ArchiveStableId($eo);
1084 $self->add_StableIdEvents($last);
1091 #warn 'Z: '.$last->ident_string.' | '.$event->ident_string."\n";
1093 $self->remove_StableIdEvent($event);
1094 $event->old_ArchiveStableId($ln);
1095 $event->new_ArchiveStableId($eo);
1096 $self->add_StableIdEvents($event);
1102 # creation followed by deletion in next mapping
1107 #warn 'Q: '.$last->ident_string.' | '.$event->ident_string."\n";
1109 $self->remove_StableIdEvent($last);
1110 $self->remove_StableIdEvent($event);
1111 $event->old_ArchiveStableId($ln);
1112 $event->new_ArchiveStableId($eo);
1113 $self->add_StableIdEvents($event);
1118 #warn 'C: '.$last->ident_string.' | '.$event->ident_string."\n";
1124 # now add ArchiveStableIds of the remaining events to the tree
1125 $self->add_ArchiveStableIds_for_events;
1131 Example : $history->reset_tree;
1132 Description : Resets all pre-calculated tree grid data. Mostly used internally
1133 by methods that modify the tree.
1144 $self->{
'sorted_tree'} = undef;
1148 =head2 current_dbname
1150 Arg[1] : (optional) String $dbname - the dbname to set
1151 Example : my $dbname = $history->current_dbname;
1152 Description : Getter/setter
for current dbname.
1153 Return type : String
1161 sub current_dbname {
1163 $self->{
'current_dbname'} = shift
if (@_);
1164 return $self->{
'current_dbname'};
1168 =head2 current_release
1170 Arg[1] : (optional) Int $release - the release to set
1171 Example : my $release = $history->current_release;
1172 Description : Getter/setter
for current release.
1181 sub current_release {
1183 $self->{
'current_release'} = shift
if (@_);
1184 return $self->{
'current_release'};
1188 =head2 current_assembly
1190 Arg[1] : (optional) String $assembly - the assembly to set
1191 Example : my $assembly = $history->current_assembly;
1192 Description : Getter/setter
for current assembly.
1193 Return type : String
1201 sub current_assembly {
1203 $self->{
'current_assembly'} = shift
if (@_);
1204 return $self->{
'current_assembly'};
1208 =head2 is_incomplete
1210 Arg[1] : (optional) Boolean $incomplete
1211 Example :
if ($history->is_incomplete) {
1212 print
"Returned tree is incomplete due to too many mappings
1213 in the database.\n";
1215 Description : Getter/setter
for incomplete flag. This is used by
1216 ArchiveStableIdAdaptor to indicate that it finished building
1217 the tree prematurely due to too many mappins in the db and can
1218 be used by applications to print warning messages.
1219 Return type : Boolean
1229 $self->{
'incomplete'} = shift
if (@_);
1230 return $self->{
'incomplete'};