0
|
1 # $Id: SimpleOntologyEngine.pm,v 1.3.2.5 2003/07/03 00:41:40 lapp Exp $
|
|
2 #
|
|
3 # BioPerl module for SimpleOntologyEngine
|
|
4 #
|
|
5 # Cared for by Peter Dimitrov <dimitrov@gnf.org>
|
|
6 #
|
|
7 # Copyright Peter Dimitrov
|
|
8 # (c) Peter Dimitrov, dimitrov@gnf.org, 2002.
|
|
9 # (c) GNF, Genomics Institute of the Novartis Research Foundation, 2002.
|
|
10 #
|
|
11 # You may distribute this module under the same terms as perl itself.
|
|
12 # Refer to the Perl Artistic License (see the license accompanying this
|
|
13 # software package, or see http://www.perl.com/language/misc/Artistic.html)
|
|
14 # for the terms under which you may use, modify, and redistribute this module.
|
|
15 #
|
|
16 # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
17 # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
18 # MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
19 #
|
|
20 # POD documentation - main docs before the code
|
|
21
|
|
22 =head1 NAME
|
|
23
|
|
24 SimpleOntologyEngine - Implementation of OntologyEngineI interface
|
|
25
|
|
26 =head1 SYNOPSIS
|
|
27
|
|
28 my $soe = Bio::Ontology::SimpleOntologyEngine->new;
|
|
29
|
|
30
|
|
31 =head1 DESCRIPTION
|
|
32
|
|
33 This is a "simple" implementation of Bio::Ontology::OntologyEngineI.
|
|
34
|
|
35 =head1 FEEDBACK
|
|
36
|
|
37 =head2 Mailing Lists
|
|
38
|
|
39 User feedback is an integral part of the evolution of this and other
|
|
40 Bioperl modules. Send your comments and suggestions preferably to
|
|
41 the Bioperl mailing list. Your participation is much appreciated.
|
|
42
|
|
43 bioperl-l@bioperl.org - General discussion
|
|
44 http://bioperl.org/MailList.shtml - About the mailing lists
|
|
45
|
|
46 =head2 Reporting Bugs
|
|
47
|
|
48 Report bugs to the Bioperl bug tracking system to help us keep track
|
|
49 of the bugs and their resolution. Bug reports can be submitted via
|
|
50 email or the web:
|
|
51
|
|
52 bioperl-bugs@bioperl.org
|
|
53 http://bioperl.org/bioperl-bugs/
|
|
54
|
|
55 =head1 AUTHOR - Peter Dimitrov
|
|
56
|
|
57 Email dimitrov@gnf.org
|
|
58
|
|
59 =head1 CONTRIBUTORS
|
|
60
|
|
61 Hilmar Lapp, hlapp at gmx.net
|
|
62
|
|
63 =head1 APPENDIX
|
|
64
|
|
65 The rest of the documentation details each of the object methods.
|
|
66 Internal methods are usually preceded with a _
|
|
67
|
|
68 =cut
|
|
69
|
|
70
|
|
71 # Let the code begin...
|
|
72
|
|
73
|
|
74 package Bio::Ontology::SimpleOntologyEngine;
|
|
75 use vars qw(@ISA);
|
|
76 use strict;
|
|
77 use Carp;
|
|
78 use Bio::Root::Root;
|
|
79 use Bio::Ontology::RelationshipFactory;
|
|
80 use Bio::Ontology::OntologyEngineI;
|
|
81 use Data::Dumper;
|
|
82
|
|
83 @ISA = qw( Bio::Root::Root Bio::Ontology::OntologyEngineI );
|
|
84
|
|
85 =head2 new
|
|
86
|
|
87 Title : new
|
|
88 Usage : $soe = Bio::Ontology::SimpleOntologyEngine->new;
|
|
89 Function: Initializes the ontology engine.
|
|
90 Example : $soe = Bio::Ontology::SimpleOntologyEngine->new;
|
|
91 Returns : Object of class SimpleOntologyEngine.
|
|
92 Args :
|
|
93
|
|
94
|
|
95 =cut
|
|
96
|
|
97 sub new{
|
|
98 my ($class, @args) = @_;
|
|
99 my $self = $class->SUPER::new(@args);
|
|
100 # my %param = @args;
|
|
101
|
|
102 $self->_term_store( {} );
|
|
103 $self->_relationship_store( {} );
|
|
104 $self->_inverted_relationship_store( {} );
|
|
105 $self->_relationship_type_store( {} );
|
|
106 $self->_instantiated_terms_store( {} );
|
|
107
|
|
108 # set defaults for the factories
|
|
109 $self->relationship_factory(Bio::Ontology::RelationshipFactory->new(
|
|
110 -type => "Bio::Ontology::Relationship"));
|
|
111 return $self;
|
|
112 }
|
|
113
|
|
114 =head2 _instantiated_terms_store
|
|
115
|
|
116 Title : _instantiated_terms_store
|
|
117 Usage : $obj->_instantiated_terms_store($newval)
|
|
118 Function:
|
|
119 Example :
|
|
120 Returns : hash
|
|
121 Args : empty hash
|
|
122
|
|
123
|
|
124 =cut
|
|
125
|
|
126 sub _instantiated_terms_store{
|
|
127 my ($self, $value) = @_;
|
|
128
|
|
129 if( defined $value) {
|
|
130 $self->{'_instantiated_terms_store'} = $value;
|
|
131 }
|
|
132 return $self->{'_instantiated_terms_store'};
|
|
133 }
|
|
134
|
|
135 =head2 mark_instantiated
|
|
136
|
|
137 Title : mark_instantiated
|
|
138 Usage : $self->mark_instantiated(TermI[] terms): TermI[]
|
|
139 Function: Marks TermI objects as fully instantiated,
|
|
140 allowing for proper counting of the number of terms in the term store.
|
|
141 The TermI objects has to be already stored in the term store in order to
|
|
142 be marked.
|
|
143 Example : $self->mark_instantiated($term);
|
|
144 Returns : its argument or throws an exception if a term is not
|
|
145 in the term store.
|
|
146 Args : array of objects of class TermI.
|
|
147
|
|
148 =cut
|
|
149
|
|
150 sub mark_instantiated{
|
|
151 my ($self, @terms) = @_;
|
|
152
|
|
153 foreach my $term (@terms) {
|
|
154 $self->throw( "term ".$term->identifier." not in the term store\n" )
|
|
155 if !defined $self->_term_store->{$term->identifier};
|
|
156 $self->_instantiated_terms_store->{$term->identifier} = 1;
|
|
157 }
|
|
158
|
|
159 return @terms;
|
|
160 }
|
|
161
|
|
162 =head2 mark_uninstantiated
|
|
163
|
|
164 Title : mark_uninstantiated
|
|
165 Usage : $self->mark_uninstantiated(TermI[] terms): TermI[]
|
|
166 Function: Marks TermI objects as not fully instantiated,
|
|
167 Example : $self->mark_uninstantiated($term);
|
|
168 Returns : its argument or throws an exception if a term is not
|
|
169 in the term store(if the term is not marked it does nothing).
|
|
170 Args : array of objects of class TermI.
|
|
171
|
|
172
|
|
173 =cut
|
|
174
|
|
175 sub mark_uninstantiated{
|
|
176 my ($self, @terms) = @_;
|
|
177
|
|
178 foreach my $term (@terms) {
|
|
179 $self->throw( "term ".$term->identifier." not in the term store\n" )
|
|
180 if !defined $self->_term_store->{$term->identifier};
|
|
181 delete $self->_instantiated_terms_store->{$term->identifier}
|
|
182 if defined $self->_instantiated_terms_store->{$term->identifier};
|
|
183 }
|
|
184
|
|
185 return @terms;
|
|
186 }
|
|
187
|
|
188 =head2 _term_store
|
|
189
|
|
190 Title : term_store
|
|
191 Usage : $obj->_term_store($newval)
|
|
192 Function:
|
|
193 Example :
|
|
194 Returns : reference to an array of Bio::Ontology::TermI objects
|
|
195 Args : reference to an array of Bio::Ontology::TermI objects
|
|
196
|
|
197 =cut
|
|
198
|
|
199 sub _term_store{
|
|
200 my ($self, $value) = @_;
|
|
201
|
|
202 if( defined $value) {
|
|
203 if ( defined $self->{'_term_store'}) {
|
|
204 $self->throw("_term_store already defined\n");
|
|
205 }
|
|
206 else {
|
|
207 $self->{'_term_store'} = $value;
|
|
208 }
|
|
209 }
|
|
210
|
|
211 return $self->{'_term_store'};
|
|
212 }
|
|
213
|
|
214 =head2 add_term
|
|
215
|
|
216 Title : add_term
|
|
217 Usage : add_term(TermI term): TermI
|
|
218 Function: Adds TermI object to the ontology engine term store.
|
|
219 Marks the term fully instantiated by default.
|
|
220 Example : $soe->add_term($term)
|
|
221 Returns : its argument.
|
|
222 Args : object of class TermI.
|
|
223
|
|
224 =cut
|
|
225
|
|
226 sub add_term{
|
|
227 my ($self, $term) = @_;
|
|
228 my $term_store = $self->_term_store;
|
|
229
|
|
230 if ( defined $term_store -> {$term->identifier}) {
|
|
231 $self->throw( "term ".$term->identifier." already defined\n" );
|
|
232 }
|
|
233 else {
|
|
234 $term_store->{$term->identifier} = $term;
|
|
235 $self->_instantiated_terms_store->{$term->identifier} = 1;
|
|
236 }
|
|
237
|
|
238 return $term;
|
|
239 }
|
|
240
|
|
241 =head2 get_term_by_identifier
|
|
242
|
|
243 Title : get_term_by_identifier
|
|
244 Usage : get_term_by_identifier(String[] id): TermI[]
|
|
245 Function: Retrieves terms from the term store by their identifier
|
|
246 field, or undef if not there.
|
|
247 Example : $term = $soe->get_term_by_identifier("IPR000001");
|
|
248 Returns : An array of zero or more Bio::Ontology::TermI objects.
|
|
249 Args : An array of identifier strings
|
|
250
|
|
251
|
|
252 =cut
|
|
253
|
|
254 sub get_term_by_identifier{
|
|
255 my ($self, @ids) = @_;
|
|
256 my @ans = ();
|
|
257
|
|
258 foreach my $id (@ids) {
|
|
259 my $term = $self->_term_store->{$id};
|
|
260 push @ans, $term if defined $term;
|
|
261 }
|
|
262
|
|
263 return @ans;
|
|
264 }
|
|
265
|
|
266 =head2 _get_number_rels
|
|
267
|
|
268 Title : get_number_rels
|
|
269 Usage :
|
|
270 Function:
|
|
271 Example :
|
|
272 Returns :
|
|
273 Args :
|
|
274
|
|
275
|
|
276 =cut
|
|
277
|
|
278 sub _get_number_rels{
|
|
279 my ($self) = @_;
|
|
280 my $num_rels = 0;
|
|
281
|
|
282 foreach my $entry ($self->_relationship_store) {
|
|
283 $num_rels += scalar keys %$entry;
|
|
284 }
|
|
285 return $num_rels;
|
|
286 }
|
|
287
|
|
288 =head2 _get_number_terms
|
|
289
|
|
290 Title : _get_number_terms
|
|
291 Usage :
|
|
292 Function:
|
|
293 Example :
|
|
294 Returns :
|
|
295 Args :
|
|
296
|
|
297
|
|
298 =cut
|
|
299
|
|
300 sub _get_number_terms{
|
|
301 my ($self) = @_;
|
|
302
|
|
303 return scalar $self->_filter_unmarked( values %{$self->_term_store} );
|
|
304
|
|
305 }
|
|
306
|
|
307 =head2 _relationship_store
|
|
308
|
|
309 Title : _storerelationship_store
|
|
310 Usage : $obj->relationship_store($newval)
|
|
311 Function:
|
|
312 Example :
|
|
313 Returns : reference to an array of Bio::Ontology::TermI objects
|
|
314 Args : reference to an array of Bio::Ontology::TermI objects
|
|
315
|
|
316
|
|
317 =cut
|
|
318
|
|
319 sub _relationship_store{
|
|
320 my ($self, $value) = @_;
|
|
321
|
|
322 if( defined $value) {
|
|
323 if ( defined $self->{'_relationship_store'}) {
|
|
324 $self->throw("_relationship_store already defined\n");
|
|
325 }
|
|
326 else {
|
|
327 $self->{'_relationship_store'} = $value;
|
|
328 }
|
|
329 }
|
|
330
|
|
331 return $self->{'_relationship_store'};
|
|
332 }
|
|
333
|
|
334 =head2 _inverted_relationship_store
|
|
335
|
|
336 Title : _inverted_relationship_store
|
|
337 Usage :
|
|
338 Function:
|
|
339 Example :
|
|
340 Returns : reference to an array of Bio::Ontology::TermI objects
|
|
341 Args : reference to an array of Bio::Ontology::TermI objects
|
|
342
|
|
343
|
|
344 =cut
|
|
345
|
|
346 sub _inverted_relationship_store{
|
|
347 my ($self, $value) = @_;
|
|
348
|
|
349 if( defined $value) {
|
|
350 if ( defined $self->{'_inverted_relationship_store'}) {
|
|
351 $self->throw("_inverted_relationship_store already defined\n");
|
|
352 }
|
|
353 else {
|
|
354 $self->{'_inverted_relationship_store'} = $value;
|
|
355 }
|
|
356 }
|
|
357
|
|
358 return $self->{'_inverted_relationship_store'};
|
|
359 }
|
|
360
|
|
361 =head2 _relationship_type_store
|
|
362
|
|
363 Title : _relationship_type_store
|
|
364 Usage : $obj->_relationship_type_store($newval)
|
|
365 Function:
|
|
366 Example :
|
|
367 Returns : reference to an array of Bio::Ontology::RelationshipType objects
|
|
368 Args : reference to an array of Bio::Ontology::RelationshipType objects
|
|
369
|
|
370
|
|
371 =cut
|
|
372
|
|
373 sub _relationship_type_store{
|
|
374 my ($self, $value) = @_;
|
|
375
|
|
376 if( defined $value) {
|
|
377 if ( defined $self->{'_relationship_type_store'}) {
|
|
378 $self->throw("_relationship_type_store already defined\n");
|
|
379 }
|
|
380 else {
|
|
381 $self->{'_relationship_type_store'} = $value;
|
|
382 }
|
|
383 }
|
|
384
|
|
385 return $self->{'_relationship_type_store'};
|
|
386 }
|
|
387
|
|
388 =head2 _add_relationship_simple
|
|
389
|
|
390 Title : _add_relationship_simple
|
|
391 Usage :
|
|
392 Function:
|
|
393 Example :
|
|
394 Returns :
|
|
395 Args :
|
|
396
|
|
397
|
|
398 =cut
|
|
399
|
|
400 sub _add_relationship_simple{
|
|
401 my ($self, $store, $rel, $inverted) = @_;
|
|
402 my $parent_id;
|
|
403 my $child_id;
|
|
404
|
|
405 if ($inverted) {
|
|
406 $parent_id = $rel->subject_term->identifier;
|
|
407 $child_id = $rel->object_term->identifier;
|
|
408 }
|
|
409 else {
|
|
410 $parent_id = $rel->object_term->identifier;
|
|
411 $child_id = $rel->subject_term->identifier;
|
|
412 }
|
|
413 if((defined $store->{$parent_id}->{$child_id}) &&
|
|
414 ($store->{$parent_id}->{$child_id}->name != $rel->predicate_term->name)){
|
|
415 $self->throw("relationship ".Dumper($rel->predicate_term).
|
|
416 " between ".$parent_id." and ".$child_id.
|
|
417 " already defined as ".
|
|
418 Dumper($store->{$parent_id}->{$child_id})."\n");
|
|
419 }
|
|
420 else {
|
|
421 $store->{$parent_id}->{$child_id} = $rel->predicate_term;
|
|
422 }
|
|
423 }
|
|
424
|
|
425 =head2 add_relationship
|
|
426
|
|
427 Title : add_relationship
|
|
428 Usage : add_relationship(RelationshipI relationship): RelationshipI
|
|
429 Function: Adds a relationship object to the ontology engine.
|
|
430 Example :
|
|
431 Returns : Its argument.
|
|
432 Args : A RelationshipI object.
|
|
433
|
|
434
|
|
435 =cut
|
|
436
|
|
437 sub add_relationship{
|
|
438 my ($self, $rel) = @_;
|
|
439
|
|
440 $self->_add_relationship_simple($self->_relationship_store,
|
|
441 $rel, 0);
|
|
442 $self->_add_relationship_simple($self->_inverted_relationship_store,
|
|
443 $rel, 1);
|
|
444 $self->_relationship_type_store->{
|
|
445 $self->_unique_termid($rel->predicate_term)} = $rel->predicate_term;
|
|
446
|
|
447 return $rel;
|
|
448 }
|
|
449
|
|
450 =head2 get_relationships
|
|
451
|
|
452 Title : get_relationships
|
|
453 Usage : get_relationships(): RelationshipI[]
|
|
454 Function: Retrieves all relationship objects.
|
|
455 Example :
|
|
456 Returns : Array of RelationshipI objects
|
|
457 Args :
|
|
458
|
|
459
|
|
460 =cut
|
|
461
|
|
462 sub get_relationships{
|
|
463 my $self = shift;
|
|
464 my $term = shift;
|
|
465 my @rels;
|
|
466 my $store = $self->_relationship_store;
|
|
467 my $relfact = $self->relationship_factory();
|
|
468
|
|
469 my @parent_ids = $term ?
|
|
470 # if a term is supplied then only get the term's parents
|
|
471 (map { $_->identifier(); } $self->get_parent_terms($term)) :
|
|
472 # otherwise use all parent ids
|
|
473 (keys %{$store});
|
|
474 # add the term as a parent too if one is supplied
|
|
475 push(@parent_ids,$term->identifier) if $term;
|
|
476
|
|
477 foreach my $parent_id (@parent_ids) {
|
|
478 my $parent_entry = $store->{$parent_id};
|
|
479
|
|
480 # if a term is supplied, add a relationship for the parent to the term
|
|
481 # except if the parent is the term itself (we added that one before)
|
|
482 if($term && ($parent_id ne $term->identifier())) {
|
|
483 my $parent_term = $self->get_term_by_identifier($parent_id);
|
|
484 push(@rels,
|
|
485 $relfact->create_object(-object_term => $parent_term,
|
|
486 -subject_term => $term,
|
|
487 -predicate_term =>
|
|
488 $parent_entry->{$term->identifier},
|
|
489 -ontology => $term->ontology()
|
|
490 )
|
|
491 );
|
|
492
|
|
493 } else {
|
|
494 # otherwise, i.e., no term supplied, or the parent equals the
|
|
495 # supplied term
|
|
496 my $parent_term = $term ?
|
|
497 $term : $self->get_term_by_identifier($parent_id);
|
|
498 foreach my $child_id (keys %$parent_entry) {
|
|
499 my $rel_info = $parent_entry->{$child_id};
|
|
500
|
|
501 push(@rels,
|
|
502 $relfact->create_object(-object_term => $parent_term,
|
|
503 -subject_term =>
|
|
504 $self->get_term_by_identifier(
|
|
505 $child_id),
|
|
506 -predicate_term => $rel_info,
|
|
507 -ontology =>$parent_term->ontology
|
|
508 )
|
|
509 );
|
|
510 }
|
|
511 }
|
|
512 }
|
|
513
|
|
514 return @rels;
|
|
515 }
|
|
516
|
|
517 =head2 get_all_relationships
|
|
518
|
|
519 Title : get_all_relationships
|
|
520 Usage : get_all_relationships(): RelationshipI[]
|
|
521 Function: Retrieves all relationship objects.
|
|
522 Example :
|
|
523 Returns : Array of RelationshipI objects
|
|
524 Args :
|
|
525
|
|
526
|
|
527 =cut
|
|
528
|
|
529 sub get_all_relationships{
|
|
530 return shift->get_relationships();
|
|
531 }
|
|
532
|
|
533 =head2 get_predicate_terms
|
|
534
|
|
535 Title : get_predicate_terms
|
|
536 Usage : get_predicate_terms(): TermI[]
|
|
537 Function: Retrives all relationship types stored in the engine
|
|
538 Example :
|
|
539 Returns : reference to an array of Bio::Ontology::RelationshipType objects
|
|
540 Args :
|
|
541
|
|
542
|
|
543 =cut
|
|
544
|
|
545 sub get_predicate_terms{
|
|
546 my ($self) = @_;
|
|
547
|
|
548 return values %{$self->_relationship_type_store};
|
|
549 }
|
|
550
|
|
551 =head2 _is_rel_type
|
|
552
|
|
553 Title : _is_rel_type
|
|
554 Usage :
|
|
555 Function:
|
|
556 Example :
|
|
557 Returns :
|
|
558 Args :
|
|
559
|
|
560
|
|
561 =cut
|
|
562
|
|
563 sub _is_rel_type{
|
|
564 my ($self, $term, @rel_types) = @_;
|
|
565
|
|
566 foreach my $rel_type (@rel_types) {
|
|
567 if($rel_type->identifier || $term->identifier) {
|
|
568 return 1 if $rel_type->identifier eq $term->identifier;
|
|
569 } else {
|
|
570 return 1 if $rel_type->name eq $term->name;
|
|
571 }
|
|
572 }
|
|
573
|
|
574 return 0;
|
|
575 }
|
|
576
|
|
577 =head2 _typed_traversal
|
|
578
|
|
579 Title : _typed_traversal
|
|
580 Usage :
|
|
581 Function:
|
|
582 Example :
|
|
583 Returns :
|
|
584 Args :
|
|
585
|
|
586
|
|
587 =cut
|
|
588
|
|
589 sub _typed_traversal{
|
|
590 my ($self, $rel_store, $level, $term_id, @rel_types) = @_;
|
|
591 return undef if !defined($rel_store->{$term_id});
|
|
592 my %parent_entry = %{$rel_store->{$term_id}};
|
|
593 my @children = keys %parent_entry;
|
|
594
|
|
595 my @ans;
|
|
596
|
|
597 if (@rel_types > 0) {
|
|
598 @ans = ();
|
|
599
|
|
600 foreach my $child_id (@children) {
|
|
601 push @ans, $child_id
|
|
602 if $self->_is_rel_type( $rel_store->{$term_id}->{$child_id},
|
|
603 @rel_types);
|
|
604 }
|
|
605 }
|
|
606 else {
|
|
607 @ans = @children;
|
|
608 }
|
|
609 if ($level < 1) {
|
|
610 my @ans1 = ();
|
|
611
|
|
612 foreach my $child_id (@ans) {
|
|
613 push @ans1, $self->_typed_traversal($rel_store,
|
|
614 $level - 1, $child_id, @rel_types)
|
|
615 if defined $rel_store->{$child_id};
|
|
616 }
|
|
617 push @ans, @ans1;
|
|
618 }
|
|
619
|
|
620 return @ans;
|
|
621 }
|
|
622
|
|
623 =head2 get_child_terms
|
|
624
|
|
625 Title : get_child_terms
|
|
626 Usage : get_child_terms(TermI term, TermI[] predicate_terms): TermI[]
|
|
627 get_child_terms(TermI term, RelationshipType[] predicate_terms): TermI[]
|
|
628 Function: Retrieves all child terms of a given term, that satisfy a
|
|
629 relationship among those that are specified in the second
|
|
630 argument or undef otherwise. get_child_terms is a special
|
|
631 case of get_descendant_terms, limiting the search to the
|
|
632 direct descendants.
|
|
633
|
|
634 Example :
|
|
635 Returns : Array of TermI objects.
|
|
636 Args : First argument is the term of interest, second is the list of relationship type terms.
|
|
637
|
|
638
|
|
639 =cut
|
|
640
|
|
641 sub get_child_terms{
|
|
642 my ($self, $term, @relationship_types) = @_;
|
|
643
|
|
644 $self->throw("must provide TermI compliant object")
|
|
645 unless defined($term) && $term->isa("Bio::Ontology::TermI");
|
|
646
|
|
647 return $self->_filter_unmarked(
|
|
648 $self->get_term_by_identifier(
|
|
649 $self->_typed_traversal($self->_relationship_store,
|
|
650 1,
|
|
651 $term->identifier,
|
|
652 @relationship_types) ) );
|
|
653 }
|
|
654
|
|
655 =head2 get_descendant_terms
|
|
656
|
|
657 Title : get_descendant_terms
|
|
658 Usage : get_descendant_terms(TermI term, TermI[] rel_types): TermI[]
|
|
659 get_child_terms(TermI term, RelationshipType[] predicate_terms): TermI[]
|
|
660 Function: Retrieves all descendant terms of a given term, that
|
|
661 satisfy a relationship among those that are specified in
|
|
662 the second argument or undef otherwise. Uses
|
|
663 _typed_traversal to find all descendants.
|
|
664
|
|
665 Example :
|
|
666 Returns : Array of TermI objects.
|
|
667 Args : First argument is the term of interest, second is the list of relationship type terms.
|
|
668
|
|
669
|
|
670 =cut
|
|
671
|
|
672 sub get_descendant_terms{
|
|
673 my ($self, $term, @relationship_types) = @_;
|
|
674
|
|
675 $self->throw("must provide TermI compliant object")
|
|
676 unless defined($term) && $term->isa("Bio::Ontology::TermI");
|
|
677
|
|
678 return $self->_filter_unmarked(
|
|
679 $self->_filter_repeated(
|
|
680 $self->get_term_by_identifier(
|
|
681 $self->_typed_traversal($self->_relationship_store,
|
|
682 0,
|
|
683 $term->identifier,
|
|
684 @relationship_types) ) ) );
|
|
685 }
|
|
686
|
|
687 =head2 get_parent_terms
|
|
688
|
|
689 Title : get_parent_terms
|
|
690 Usage : get_parent_terms(TermI term, TermI[] predicate_terms): TermI[]
|
|
691 get_child_terms(TermI term, RelationshipType[] predicate_terms): TermI[]
|
|
692 Function: Retrieves all parent terms of a given term, that satisfy a
|
|
693 relationship among those that are specified in the second
|
|
694 argument or undef otherwise. get_parent_terms is a special
|
|
695 case of get_ancestor_terms, limiting the search to the
|
|
696 direct ancestors.
|
|
697
|
|
698 Example :
|
|
699 Returns : Array of TermI objects.
|
|
700 Args : First argument is the term of interest, second is the list of relationship type terms.
|
|
701
|
|
702
|
|
703 =cut
|
|
704
|
|
705 sub get_parent_terms{
|
|
706 my ($self, $term, @relationship_types) = @_;
|
|
707 $self->throw("term must be a valid object, not undef") unless defined $term;
|
|
708
|
|
709 return $self->_filter_unmarked(
|
|
710 $self->get_term_by_identifier(
|
|
711 $self->_typed_traversal($self->_inverted_relationship_store,
|
|
712 1,
|
|
713 $term->identifier,
|
|
714 @relationship_types) ) );
|
|
715 }
|
|
716
|
|
717 =head2 get_ancestor_terms
|
|
718
|
|
719 Title : get_ancestor_terms
|
|
720 Usage : get_ancestor_terms(TermI term, TermI[] predicate_terms): TermI[]
|
|
721 get_child_terms(TermI term, RelationshipType[] predicate_terms): TermI[]
|
|
722 Function: Retrieves all ancestor terms of a given term, that satisfy
|
|
723 a relationship among those that are specified in the second
|
|
724 argument or undef otherwise. Uses _typed_traversal to find
|
|
725 all ancestors.
|
|
726
|
|
727 Example :
|
|
728 Returns : Array of TermI objects.
|
|
729 Args : First argument is the term of interest, second is the list
|
|
730 of relationship type terms.
|
|
731
|
|
732
|
|
733 =cut
|
|
734
|
|
735 sub get_ancestor_terms{
|
|
736 my ($self, $term, @relationship_types) = @_;
|
|
737 $self->throw("term must be a valid object, not undef") unless defined $term;
|
|
738
|
|
739 return $self->_filter_unmarked(
|
|
740 $self->_filter_repeated(
|
|
741 $self->get_term_by_identifier(
|
|
742 $self->_typed_traversal($self->_inverted_relationship_store,
|
|
743 0,
|
|
744 $term->identifier,
|
|
745 @relationship_types) ) ) );
|
|
746 }
|
|
747
|
|
748 =head2 get_leaf_terms
|
|
749
|
|
750 Title : get_leaf_terms
|
|
751 Usage : get_leaf_terms(): TermI[]
|
|
752 Function: Retrieves all leaf terms from the ontology. Leaf term is a term w/o descendants.
|
|
753 Example : @leaf_terms = $obj->get_leaf_terms()
|
|
754 Returns : Array of TermI objects.
|
|
755 Args :
|
|
756
|
|
757
|
|
758 =cut
|
|
759
|
|
760 sub get_leaf_terms{
|
|
761 my ($self) = @_;
|
|
762 my @leaf_terms;
|
|
763
|
|
764 foreach my $term (values %{$self->_term_store}) {
|
|
765 push @leaf_terms, $term
|
|
766 if !defined $self->_relationship_store->{$term->identifier} &&
|
|
767 defined $self->_instantiated_terms_store->{$term->identifier};
|
|
768 }
|
|
769
|
|
770 return @leaf_terms;
|
|
771 }
|
|
772
|
|
773 =head2 get_root_terms
|
|
774
|
|
775 Title : get_root_terms
|
|
776 Usage : get_root_terms(): TermI[]
|
|
777 Function: Retrieves all root terms from the ontology. Root term is a term w/o descendants.
|
|
778 Example : @root_terms = $obj->get_root_terms()
|
|
779 Returns : Array of TermI objects.
|
|
780 Args :
|
|
781
|
|
782
|
|
783 =cut
|
|
784
|
|
785 sub get_root_terms{
|
|
786 my ($self) = @_;
|
|
787 my @root_terms;
|
|
788
|
|
789 foreach my $term (values %{$self->_term_store}) {
|
|
790 push @root_terms, $term
|
|
791 if !defined $self->_inverted_relationship_store->{$term->identifier} &&
|
|
792 defined $self->_instantiated_terms_store->{$term->identifier};
|
|
793 }
|
|
794
|
|
795 return @root_terms;
|
|
796 }
|
|
797
|
|
798 =head2 _filter_repeated
|
|
799
|
|
800 Title : _filter_repeated
|
|
801 Usage : @lst = $self->_filter_repeated(@old_lst);
|
|
802 Function: Removes repeated terms
|
|
803 Example :
|
|
804 Returns : List of unique TermI objects
|
|
805 Args : List of TermI objects
|
|
806
|
|
807
|
|
808 =cut
|
|
809
|
|
810 sub _filter_repeated{
|
|
811 my ($self, @args) = @_;
|
|
812 my %h;
|
|
813
|
|
814 foreach my $element (@args) {
|
|
815 $h{$element->identifier} = $element if !defined $h{$element->identifier};
|
|
816 }
|
|
817
|
|
818 return values %h;
|
|
819 }
|
|
820
|
|
821 =head2 get_all_terms
|
|
822
|
|
823 Title : get_all_terms
|
|
824 Usage : get_all_terms(): TermI[]
|
|
825 Function: Retrieves all terms currently stored in the ontology.
|
|
826 Example : @all_terms = $obj->get_all_terms()
|
|
827 Returns : Array of TermI objects.
|
|
828 Args :
|
|
829
|
|
830
|
|
831 =cut
|
|
832
|
|
833 sub get_all_terms{
|
|
834 my ($self) = @_;
|
|
835
|
|
836 return $self->_filter_unmarked( values %{$self->_term_store} );
|
|
837 }
|
|
838
|
|
839 =head2 find_terms
|
|
840
|
|
841 Title : find_terms
|
|
842 Usage : ($term) = $oe->find_terms(-identifier => "SO:0000263");
|
|
843 Function: Find term instances matching queries for their attributes.
|
|
844
|
|
845 This implementation can efficiently resolve queries by
|
|
846 identifier.
|
|
847
|
|
848 Example :
|
|
849 Returns : an array of zero or more Bio::Ontology::TermI objects
|
|
850 Args : Named parameters. The following parameters should be recognized
|
|
851 by any implementations:
|
|
852
|
|
853 -identifier query by the given identifier
|
|
854 -name query by the given name
|
|
855
|
|
856
|
|
857 =cut
|
|
858
|
|
859 sub find_terms{
|
|
860 my ($self,@args) = @_;
|
|
861 my @terms;
|
|
862
|
|
863 my ($id,$name) = $self->_rearrange([qw(IDENTIFIER NAME)],@args);
|
|
864
|
|
865 if(defined($id)) {
|
|
866 @terms = $self->get_term_by_identifier($id);
|
|
867 } else {
|
|
868 @terms = $self->get_all_terms();
|
|
869 }
|
|
870 if(defined($name)) {
|
|
871 @terms = grep { $_->name() eq $name; } @terms;
|
|
872 }
|
|
873 return @terms;
|
|
874 }
|
|
875
|
|
876
|
|
877 =head2 relationship_factory
|
|
878
|
|
879 Title : relationship_factory
|
|
880 Usage : $fact = $obj->relationship_factory()
|
|
881 Function: Get/set the object factory to be used when relationship
|
|
882 objects are created by the implementation on-the-fly.
|
|
883
|
|
884 Example :
|
|
885 Returns : value of relationship_factory (a Bio::Factory::ObjectFactoryI
|
|
886 compliant object)
|
|
887 Args : on set, a Bio::Factory::ObjectFactoryI compliant object
|
|
888
|
|
889
|
|
890 =cut
|
|
891
|
|
892 sub relationship_factory{
|
|
893 my $self = shift;
|
|
894
|
|
895 return $self->{'relationship_factory'} = shift if @_;
|
|
896 return $self->{'relationship_factory'};
|
|
897 }
|
|
898
|
|
899 =head2 term_factory
|
|
900
|
|
901 Title : term_factory
|
|
902 Usage : $fact = $obj->term_factory()
|
|
903 Function: Get/set the object factory to be used when term objects are
|
|
904 created by the implementation on-the-fly.
|
|
905
|
|
906 Note that this ontology engine implementation does not
|
|
907 create term objects on the fly, and therefore setting this
|
|
908 attribute is meaningless.
|
|
909
|
|
910 Example :
|
|
911 Returns : value of term_factory (a Bio::Factory::ObjectFactoryI
|
|
912 compliant object)
|
|
913 Args : on set, a Bio::Factory::ObjectFactoryI compliant object
|
|
914
|
|
915
|
|
916 =cut
|
|
917
|
|
918 sub term_factory{
|
|
919 my $self = shift;
|
|
920
|
|
921 if(@_) {
|
|
922 $self->warn("setting term factory, but ".ref($self).
|
|
923 " does not create terms on-the-fly");
|
|
924 return $self->{'term_factory'} = shift;
|
|
925 }
|
|
926 return $self->{'term_factory'};
|
|
927 }
|
|
928
|
|
929 =head2 _filter_unmarked
|
|
930
|
|
931 Title : _filter_unmarked
|
|
932 Usage : _filter_unmarked(TermI[] terms): TermI[]
|
|
933 Function: Removes the uninstantiated terms from the list of terms
|
|
934 Example :
|
|
935 Returns : array of fully instantiated TermI objects
|
|
936 Args : array of TermI objects
|
|
937
|
|
938
|
|
939 =cut
|
|
940
|
|
941 sub _filter_unmarked{
|
|
942 my ($self, @terms) = @_;
|
|
943 my @filtered_terms = ();
|
|
944
|
|
945 if ( scalar(@terms) >= 1) {
|
|
946 foreach my $term (@terms) {
|
|
947 push @filtered_terms, $term
|
|
948 if defined $self->_instantiated_terms_store->{$term->identifier};
|
|
949 }
|
|
950 }
|
|
951
|
|
952 return @filtered_terms;
|
|
953 }
|
|
954
|
|
955 =head2 remove_term_by_id
|
|
956
|
|
957 Title : remove_term_by_id
|
|
958 Usage : remove_term_by_id(String id): TermI
|
|
959 Function: Removes TermI object from the ontology engine using the
|
|
960 string id as an identifier. Current implementation does not
|
|
961 enforce consistency of the relationships using that term.
|
|
962 Example : $term = $soe->remove_term_by_id($id);
|
|
963 Returns : Object of class TermI or undef if not found.
|
|
964 Args : The string identifier of a term.
|
|
965
|
|
966
|
|
967 =cut
|
|
968
|
|
969 sub remove_term_by_id{
|
|
970 my ($self, $id) = @_;
|
|
971
|
|
972 if ( $self->get_term_by_identifier($id) ) {
|
|
973 my $term = $self->{_term_store}->{$id};
|
|
974 delete $self->{_term_store}->{$id};
|
|
975 return $term;
|
|
976 }
|
|
977 else {
|
|
978 $self->warn("Term with id '$id' is not in the term store");
|
|
979 return undef;
|
|
980 }
|
|
981 }
|
|
982
|
|
983 =head2 to_string
|
|
984
|
|
985 Title : to_string
|
|
986 Usage : print $sv->to_string();
|
|
987 Function: Currently returns formatted string containing the number of
|
|
988 terms and number of relationships from the ontology engine.
|
|
989 Example : print $sv->to_string();
|
|
990 Returns :
|
|
991 Args :
|
|
992
|
|
993
|
|
994 =cut
|
|
995
|
|
996 sub to_string{
|
|
997 my ($self) = @_;
|
|
998 my $s = "";
|
|
999
|
|
1000 $s .= "-- # Terms:\n";
|
|
1001 $s .= scalar($self->get_all_terms)."\n";
|
|
1002 $s .= "-- # Relationships:\n";
|
|
1003 $s .= $self->_get_number_rels."\n";
|
|
1004
|
|
1005 return $s;
|
|
1006 }
|
|
1007
|
|
1008 =head2 _unique_termid
|
|
1009
|
|
1010 Title : _unique_termid
|
|
1011 Usage :
|
|
1012 Function: Returns a string that can be used as ID using fail-over
|
|
1013 approaches.
|
|
1014
|
|
1015 If the identifier attribute is not set, it uses the
|
|
1016 combination of name and ontology name, provided both are
|
|
1017 set. If they aren't, it returns the name alone.
|
|
1018
|
|
1019 Note that this is a private method. Call from inheriting
|
|
1020 classes but not from outside.
|
|
1021
|
|
1022 Example :
|
|
1023 Returns : a string
|
|
1024 Args : a Bio::Ontology::TermI compliant object
|
|
1025
|
|
1026
|
|
1027 =cut
|
|
1028
|
|
1029 sub _unique_termid{
|
|
1030 my $self = shift;
|
|
1031 my $term = shift;
|
|
1032
|
|
1033 return $term->identifier() if $term->identifier();
|
|
1034 my $id = $term->ontology->name() if $term->ontology();
|
|
1035 if($id) {
|
|
1036 $id .= '|';
|
|
1037 } else {
|
|
1038 $id = '';
|
|
1039 }
|
|
1040 $id .= $term->name();
|
|
1041 }
|
|
1042
|
|
1043
|
|
1044 #################################################################
|
|
1045 # aliases
|
|
1046 #################################################################
|
|
1047
|
|
1048 *get_relationship_types = \&get_predicate_terms;
|
|
1049
|
|
1050 1;
|