moved to: https://sites.google.com/site/cmzmasek/home/software/forester
[jalview.git] / forester / java / src / org / forester / surfacing / DomainArchitectureBasedGenomeSimilarityCalculator.java
1 // $Id:
2 // 19:38:35 cmzmasek Exp $
3 // FORESTER -- software libraries and applications
4 // for evolutionary biology research and applications.
5 //
6 // Copyright (C) 2008-2009 Christian M. Zmasek
7 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
8 // All rights reserved
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 //
24 // Contact: phylosoft @ gmail . com
25 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
26
27 package org.forester.surfacing;
28
29 import java.util.HashSet;
30 import java.util.Set;
31
32 import org.forester.protein.BinaryDomainCombination;
33 import org.forester.protein.DomainId;
34
35 public class DomainArchitectureBasedGenomeSimilarityCalculator {
36
37     public static final double                MAX_SIMILARITY_SCORE = 1.0;
38     public static final double                MIN_SIMILARITY_SCORE = 0.0;
39     final private GenomeWideCombinableDomains _combinable_domains_genome_0;
40     final private GenomeWideCombinableDomains _combinable_domains_genome_1;
41     private Set<DomainId>                     _domain_ids_to_ignore;
42     private boolean                           _allow_domains_to_be_ignored;
43     private Set<DomainId>                     _all_domains;
44     private Set<DomainId>                     _shared_domains;
45     private Set<DomainId>                     _domains_specific_to_0;
46     private Set<DomainId>                     _domains_specific_to_1;
47     private Set<BinaryDomainCombination>      _all_binary_domain_combinations;
48     private Set<BinaryDomainCombination>      _shared_binary_domain_combinations;
49     private Set<BinaryDomainCombination>      _binary_domain_combinations_specific_to_0;
50     private Set<BinaryDomainCombination>      _binary_domain_combinations_specific_to_1;
51
52     public DomainArchitectureBasedGenomeSimilarityCalculator( final GenomeWideCombinableDomains combinable_domains_genome_0,
53                                                               final GenomeWideCombinableDomains combinable_domains_genome_1 ) {
54         if ( ( combinable_domains_genome_0 == null ) || ( combinable_domains_genome_0.getSize() < 1 )
55                 || ( combinable_domains_genome_1 == null ) || ( combinable_domains_genome_1.getSize() < 1 ) ) {
56             throw new IllegalArgumentException( "attempt to compare null or empty combinable domains collection" );
57         }
58         if ( combinable_domains_genome_0.getSpecies().equals( combinable_domains_genome_1.getSpecies() ) ) {
59             throw new IllegalArgumentException( "attempt to compare combinable domains collection from the same species" );
60         }
61         _combinable_domains_genome_0 = combinable_domains_genome_0;
62         _combinable_domains_genome_1 = combinable_domains_genome_1;
63         init();
64         forceRecalculation();
65     }
66
67     public void addDomainIdToIgnore( final DomainId domain_id_to_ignore ) {
68         forceRecalculation();
69         getDomainIdsToIgnore().add( domain_id_to_ignore );
70     }
71
72     /**
73      * This returns a score between 0.0 (no binary domain combination in common) 
74      * and 1.0 (all binary domain combinations in common) measuring the similarity between two
75      * genomes based on the number of shared binary domain combinations:
76      *   
77      * t: sum of (distinct) binary domain combinations
78      * s: sum of shared (distinct) binary domain combinations
79      *
80      * 1 - ( ( t - s ) / t )
81      *  
82      * @return shared binary domain combinations based similarity score 
83      */
84     public double calculateSharedBinaryDomainCombinationBasedGenomeSimilarityScore() {
85         final double t = getAllBinaryDomainCombinations().size();
86         final double s = getSharedBinaryDomainCombinations().size();
87         if ( t == 0.0 ) {
88             return MIN_SIMILARITY_SCORE;
89         }
90         return ( MAX_SIMILARITY_SCORE - ( ( t - s ) / t ) );
91     }
92
93     /**
94      * This returns a score between 0.0 (no domains in common) 
95      * and 1.0 (all domains in common) measuring the similarity between two
96      * genomes based on the number of shared domains:
97      * 
98      * t: sum of (distinct) domains
99      * s: sum of shared (distinct) domains
100      *
101      * 1 - ( ( t - s ) / t )
102      * 
103      * @return shared domains based similarity score 
104      */
105     public double calculateSharedDomainsBasedGenomeSimilarityScore() {
106         final double t = getAllDomains().size();
107         final double s = getSharedDomains().size();
108         if ( t == 0.0 ) {
109             return MIN_SIMILARITY_SCORE;
110         }
111         return ( MAX_SIMILARITY_SCORE - ( ( t - s ) / t ) );
112     }
113
114     public void deleteAllDomainIdsToIgnore() {
115         forceRecalculation();
116         setDomainIdsToIgnore( new HashSet<DomainId>() );
117     }
118
119     private void forceRecalculation() {
120         _all_domains = null;
121         _shared_domains = null;
122         _domains_specific_to_0 = null;
123         _domains_specific_to_1 = null;
124         _all_binary_domain_combinations = null;
125         _shared_binary_domain_combinations = null;
126         _binary_domain_combinations_specific_to_0 = null;
127         _binary_domain_combinations_specific_to_1 = null;
128     }
129
130     /**
131      * Does not return binary combinations which contain one or two domains
132      * to be ignored -- if ignoring is allowed.
133      * 
134      * @return SortedSet<BinaryDomainCombination>
135      */
136     public Set<BinaryDomainCombination> getAllBinaryDomainCombinations() {
137         if ( _all_binary_domain_combinations == null ) {
138             final Set<BinaryDomainCombination> all = new HashSet<BinaryDomainCombination>();
139             all.addAll( getCombinableDomainsGenome0().toBinaryDomainCombinations() );
140             all.addAll( getCombinableDomainsGenome1().toBinaryDomainCombinations() );
141             if ( isAllowDomainsToBeIgnored() && !getDomainIdsToIgnore().isEmpty() ) {
142                 _all_binary_domain_combinations = pruneBinaryCombinations( all );
143             }
144             else {
145                 _all_binary_domain_combinations = all;
146             }
147         }
148         return _all_binary_domain_combinations;
149     }
150
151     /**
152      * Does not return domains which are to be
153      * ignored -- if ignoring is allowed.
154      * 
155      * 
156      * @return
157      */
158     public Set<DomainId> getAllDomains() {
159         if ( _all_domains == null ) {
160             final Set<DomainId> all = new HashSet<DomainId>();
161             all.addAll( getCombinableDomainsGenome0().getAllDomainIds() );
162             all.addAll( getCombinableDomainsGenome1().getAllDomainIds() );
163             if ( isAllowDomainsToBeIgnored() && !getDomainIdsToIgnore().isEmpty() ) {
164                 _all_domains = pruneDomains( all );
165             }
166             else {
167                 _all_domains = all;
168             }
169         }
170         return _all_domains;
171     }
172
173     private Set<BinaryDomainCombination> getBinaryDomainCombinationsSpecificToGenome( final boolean specific_to_genome_0 ) {
174         final Set<BinaryDomainCombination> specific = new HashSet<BinaryDomainCombination>();
175         final Set<BinaryDomainCombination> bc0 = getCombinableDomainsGenome0().toBinaryDomainCombinations();
176         final Set<BinaryDomainCombination> bc1 = getCombinableDomainsGenome1().toBinaryDomainCombinations();
177         if ( specific_to_genome_0 ) {
178             for( final BinaryDomainCombination binary_domain_combination0 : bc0 ) {
179                 if ( !bc1.contains( binary_domain_combination0 ) ) {
180                     specific.add( binary_domain_combination0 );
181                 }
182             }
183         }
184         else {
185             for( final BinaryDomainCombination binary_domain_combination1 : bc1 ) {
186                 if ( !bc0.contains( binary_domain_combination1 ) ) {
187                     specific.add( binary_domain_combination1 );
188                 }
189             }
190         }
191         if ( isAllowDomainsToBeIgnored() && !getDomainIdsToIgnore().isEmpty() ) {
192             return pruneBinaryCombinations( specific );
193         }
194         return specific;
195     }
196
197     public Set<BinaryDomainCombination> getBinaryDomainCombinationsSpecificToGenome0() {
198         if ( _binary_domain_combinations_specific_to_0 == null ) {
199             _binary_domain_combinations_specific_to_0 = getBinaryDomainCombinationsSpecificToGenome( true );
200         }
201         return _binary_domain_combinations_specific_to_0;
202     }
203
204     public Set<BinaryDomainCombination> getBinaryDomainCombinationsSpecificToGenome1() {
205         if ( _binary_domain_combinations_specific_to_1 == null ) {
206             _binary_domain_combinations_specific_to_1 = getBinaryDomainCombinationsSpecificToGenome( false );
207         }
208         return _binary_domain_combinations_specific_to_1;
209     }
210
211     private GenomeWideCombinableDomains getCombinableDomainsGenome0() {
212         return _combinable_domains_genome_0;
213     }
214
215     private GenomeWideCombinableDomains getCombinableDomainsGenome1() {
216         return _combinable_domains_genome_1;
217     }
218
219     private Set<DomainId> getDomainIdsToIgnore() {
220         return _domain_ids_to_ignore;
221     }
222
223     private Set<DomainId> getDomainsSpecificToGenome( final boolean specific_to_genome_0 ) {
224         final Set<DomainId> specific = new HashSet<DomainId>();
225         final Set<DomainId> d0 = getCombinableDomainsGenome0().getAllDomainIds();
226         final Set<DomainId> d1 = getCombinableDomainsGenome1().getAllDomainIds();
227         if ( specific_to_genome_0 ) {
228             for( final DomainId domain0 : d0 ) {
229                 if ( !d1.contains( domain0 ) ) {
230                     specific.add( domain0 );
231                 }
232             }
233         }
234         else {
235             for( final DomainId domain1 : d1 ) {
236                 if ( !d0.contains( domain1 ) ) {
237                     specific.add( domain1 );
238                 }
239             }
240         }
241         if ( isAllowDomainsToBeIgnored() && !getDomainIdsToIgnore().isEmpty() ) {
242             return pruneDomains( specific );
243         }
244         return specific;
245     }
246
247     public Set<DomainId> getDomainsSpecificToGenome0() {
248         if ( _domains_specific_to_0 == null ) {
249             _domains_specific_to_0 = getDomainsSpecificToGenome( true );
250         }
251         return _domains_specific_to_0;
252     }
253
254     public Set<DomainId> getDomainsSpecificToGenome1() {
255         if ( _domains_specific_to_1 == null ) {
256             _domains_specific_to_1 = getDomainsSpecificToGenome( false );
257         }
258         return _domains_specific_to_1;
259     }
260
261     public Set<BinaryDomainCombination> getSharedBinaryDomainCombinations() {
262         if ( _shared_binary_domain_combinations == null ) {
263             final Set<BinaryDomainCombination> shared = new HashSet<BinaryDomainCombination>();
264             final Set<BinaryDomainCombination> bc0 = getCombinableDomainsGenome0().toBinaryDomainCombinations();
265             final Set<BinaryDomainCombination> bc1 = getCombinableDomainsGenome1().toBinaryDomainCombinations();
266             for( final BinaryDomainCombination binary_domain_combination0 : bc0 ) {
267                 if ( bc1.contains( binary_domain_combination0 ) ) {
268                     shared.add( binary_domain_combination0 );
269                 }
270             }
271             _shared_binary_domain_combinations = shared;
272             if ( isAllowDomainsToBeIgnored() && !getDomainIdsToIgnore().isEmpty() ) {
273                 _shared_binary_domain_combinations = pruneBinaryCombinations( shared );
274             }
275         }
276         return _shared_binary_domain_combinations;
277     }
278
279     public Set<DomainId> getSharedDomains() {
280         if ( _shared_domains == null ) {
281             final Set<DomainId> shared = new HashSet<DomainId>();
282             final Set<DomainId> d0 = getCombinableDomainsGenome0().getAllDomainIds();
283             final Set<DomainId> d1 = getCombinableDomainsGenome1().getAllDomainIds();
284             for( final DomainId domain0 : d0 ) {
285                 if ( d1.contains( domain0 ) ) {
286                     shared.add( domain0 );
287                 }
288             }
289             _shared_domains = shared;
290             if ( isAllowDomainsToBeIgnored() && !getDomainIdsToIgnore().isEmpty() ) {
291                 _shared_domains = pruneDomains( shared );
292             }
293         }
294         return _shared_domains;
295     }
296
297     private void init() {
298         deleteAllDomainIdsToIgnore();
299         setAllowDomainsToBeIgnored( false );
300     }
301
302     private boolean isAllowDomainsToBeIgnored() {
303         return _allow_domains_to_be_ignored;
304     }
305
306     private Set<BinaryDomainCombination> pruneBinaryCombinations( final Set<BinaryDomainCombination> all ) {
307         final Set<BinaryDomainCombination> pruned = new HashSet<BinaryDomainCombination>();
308         for( final BinaryDomainCombination bc : all ) {
309             if ( ( !getDomainIdsToIgnore().contains( bc.getId0() ) )
310                     && ( !getDomainIdsToIgnore().contains( bc.getId1() ) ) ) {
311                 pruned.add( bc );
312             }
313         }
314         return pruned;
315     }
316
317     private Set<DomainId> pruneDomains( final Set<DomainId> all ) {
318         final Set<DomainId> pruned = new HashSet<DomainId>();
319         for( final DomainId d : all ) {
320             if ( !getDomainIdsToIgnore().contains( d ) ) {
321                 pruned.add( d );
322             }
323         }
324         return pruned;
325     }
326
327     public void setAllowDomainsToBeIgnored( final boolean allow_domains_to_be_ignored ) {
328         forceRecalculation();
329         _allow_domains_to_be_ignored = allow_domains_to_be_ignored;
330     }
331
332     void setDomainIdsToIgnore( final Set<DomainId> domain_ids_to_ignore ) {
333         forceRecalculation();
334         _domain_ids_to_ignore = domain_ids_to_ignore;
335     }
336 }