Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.datamodel

File AlignedCodonFrame.java

 

Coverage histogram

../../img/srcFileCovDistChart9.png
12% of files have more coverage

Code metrics

102
188
34
2
786
456
105
0.56
5.53
17
3.09

Classes

Class Line # Actions
AlignedCodonFrame 34 176 96 44
0.8533333585.3%
AlignedCodonFrame.SequenceToSequenceMapping 40 12 9 10
0.583333358.3%
 

Contributing tests

This file is covered by 80 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.datamodel;
22   
23    import jalview.util.MapList;
24    import jalview.util.MappingUtils;
25   
26    import java.util.AbstractList;
27    import java.util.ArrayList;
28    import java.util.List;
29   
30    /**
31    * Stores mapping between the columns of a protein alignment and a DNA alignment
32    * and a list of individual codon to amino acid mappings between sequences.
33    */
 
34    public class AlignedCodonFrame
35    {
36   
37    /*
38    * Data bean to hold mappings from one sequence to another
39    */
 
40    public class SequenceToSequenceMapping
41    {
42    private SequenceI fromSeq;
43   
44    private Mapping mapping;
45   
 
46  377 toggle SequenceToSequenceMapping(SequenceI from, Mapping map)
47    {
48  377 this.fromSeq = from;
49  377 this.mapping = map;
50    }
51   
52    /**
53    * Readable representation for debugging only, not guaranteed not to change
54    */
 
55  0 toggle @Override
56    public String toString()
57    {
58  0 return String.format("From %s %s", fromSeq.getName(),
59    mapping.toString());
60    }
61   
62    /**
63    * Returns a hashCode derived from the hashcodes of the mappings and fromSeq
64    *
65    * @see SequenceToSequenceMapping#hashCode()
66    */
 
67  0 toggle @Override
68    public int hashCode()
69    {
70  0 return (fromSeq == null ? 0 : fromSeq.hashCode() * 31)
71    + mapping.hashCode();
72    }
73   
74    /**
75    * Answers true if the objects hold the same mapping between the same two
76    * sequences
77    *
78    * @see Mapping#equals
79    */
 
80  150 toggle @Override
81    public boolean equals(Object obj)
82    {
83  150 if (!(obj instanceof SequenceToSequenceMapping))
84    {
85  0 return false;
86    }
87  150 SequenceToSequenceMapping that = (SequenceToSequenceMapping) obj;
88  150 if (this.mapping == null)
89    {
90  0 return that.mapping == null;
91    }
92    // TODO: can simplify by asserting fromSeq is a dataset sequence
93  150 return (this.fromSeq == that.fromSeq
94    || (this.fromSeq != null && that.fromSeq != null
95    && this.fromSeq.getDatasetSequence() != null
96    && this.fromSeq.getDatasetSequence() == that.fromSeq
97    .getDatasetSequence()))
98    && this.mapping.equals(that.mapping);
99    }
100   
 
101  14 toggle public SequenceI getFromSeq()
102    {
103  14 return fromSeq;
104    }
105   
 
106  28 toggle public Mapping getMapping()
107    {
108  28 return mapping;
109    }
110    }
111   
112    private List<SequenceToSequenceMapping> mappings;
113   
114    /**
115    * Constructor
116    */
 
117  165 toggle public AlignedCodonFrame()
118    {
119  165 mappings = new ArrayList<SequenceToSequenceMapping>();
120    }
121   
122    /**
123    * Adds a mapping between the dataset sequences for the associated dna and
124    * protein sequence objects
125    *
126    * @param dnaseq
127    * @param aaseq
128    * @param map
129    */
 
130  383 toggle public void addMap(SequenceI dnaseq, SequenceI aaseq, MapList map)
131    {
132  383 addMap(dnaseq, aaseq, map, null);
133    }
134   
135    /**
136    * Adds a mapping between the dataset sequences for the associated dna and
137    * protein sequence objects
138    *
139    * @param dnaseq
140    * @param aaseq
141    * @param map
142    * @param mapFromId
143    */
 
144  385 toggle public void addMap(SequenceI dnaseq, SequenceI aaseq, MapList map,
145    String mapFromId)
146    {
147    // JBPNote DEBUG! THIS !
148    // dnaseq.transferAnnotation(aaseq, mp);
149    // aaseq.transferAnnotation(dnaseq, new Mapping(map.getInverse()));
150   
151  385 SequenceI fromSeq = (dnaseq.getDatasetSequence() == null) ? dnaseq
152    : dnaseq.getDatasetSequence();
153  385 SequenceI toSeq = (aaseq.getDatasetSequence() == null) ? aaseq
154    : aaseq.getDatasetSequence();
155   
156    /*
157    * if we already hold a mapping between these sequences, just add to it
158    * note that 'adding' a duplicate map does nothing; this protects against
159    * creating duplicate mappings in AlignedCodonFrame
160    */
161  385 for (SequenceToSequenceMapping ssm : mappings)
162    {
163  1125 if (ssm.fromSeq == fromSeq && ssm.mapping.to == toSeq)
164    {
165  8 ssm.mapping.map.addMapList(map);
166  8 return;
167    }
168    }
169   
170    /*
171    * otherwise, add a new sequence mapping
172    */
173  377 Mapping mp = new Mapping(toSeq, map);
174  377 mp.setMappedFromId(mapFromId);
175  377 mappings.add(new SequenceToSequenceMapping(fromSeq, mp));
176    }
177   
 
178  44 toggle public SequenceI[] getdnaSeqs()
179    {
180    // TODO return a list instead?
181    // return dnaSeqs;
182  44 List<SequenceI> seqs = new ArrayList<SequenceI>();
183  44 for (SequenceToSequenceMapping ssm : mappings)
184    {
185  52 seqs.add(ssm.fromSeq);
186    }
187  44 return seqs.toArray(new SequenceI[seqs.size()]);
188    }
189   
 
190  16 toggle public SequenceI[] getAaSeqs()
191    {
192    // TODO not used - remove?
193  16 List<SequenceI> seqs = new ArrayList<SequenceI>();
194  16 for (SequenceToSequenceMapping ssm : mappings)
195    {
196  16 seqs.add(ssm.mapping.to);
197    }
198  16 return seqs.toArray(new SequenceI[seqs.size()]);
199    }
200   
 
201  44 toggle public MapList[] getdnaToProt()
202    {
203  44 List<MapList> maps = new ArrayList<MapList>();
204  44 for (SequenceToSequenceMapping ssm : mappings)
205    {
206  44 maps.add(ssm.mapping.map);
207    }
208  44 return maps.toArray(new MapList[maps.size()]);
209    }
210   
 
211  8 toggle public Mapping[] getProtMappings()
212    {
213  8 List<Mapping> maps = new ArrayList<Mapping>();
214  8 for (SequenceToSequenceMapping ssm : mappings)
215    {
216  9 maps.add(ssm.mapping);
217    }
218  8 return maps.toArray(new Mapping[maps.size()]);
219    }
220   
221    /**
222    * Returns the first mapping found which is to or from the given sequence, or
223    * null.
224    *
225    * @param seq
226    * @return
227    */
 
228  10 toggle public Mapping getMappingForSequence(SequenceI seq)
229    {
230  10 SequenceI seqDs = seq.getDatasetSequence();
231  10 seqDs = seqDs != null ? seqDs : seq;
232   
233  10 for (SequenceToSequenceMapping ssm : mappings)
234    {
235  18 if (ssm.fromSeq == seqDs || ssm.mapping.to == seqDs)
236    {
237  10 return ssm.mapping;
238    }
239    }
240  0 return null;
241    }
242   
243    /**
244    * Return the corresponding aligned or dataset aa sequence for given dna
245    * sequence, null if not found.
246    *
247    * @param sequenceRef
248    * @return
249    */
 
250  341 toggle public SequenceI getAaForDnaSeq(SequenceI dnaSeqRef)
251    {
252  341 SequenceI dnads = dnaSeqRef.getDatasetSequence();
253  341 for (SequenceToSequenceMapping ssm : mappings)
254    {
255  372 if (ssm.fromSeq == dnaSeqRef || ssm.fromSeq == dnads)
256    {
257  89 return ssm.mapping.to;
258    }
259    }
260  252 return null;
261    }
262   
263    /**
264    *
265    * @param sequenceRef
266    * @return null or corresponding aaSeq entry for dnaSeq entry
267    */
 
268  276 toggle public SequenceI getDnaForAaSeq(SequenceI aaSeqRef)
269    {
270  276 SequenceI aads = aaSeqRef.getDatasetSequence();
271  276 for (SequenceToSequenceMapping ssm : mappings)
272    {
273  305 if (ssm.mapping.to == aaSeqRef || ssm.mapping.to == aads)
274    {
275  89 return ssm.fromSeq;
276    }
277    }
278  187 return null;
279    }
280   
281    /**
282    * test to see if codon frame involves seq in any way
283    *
284    * @param seq
285    * a nucleotide or protein sequence
286    * @return true if a mapping exists to or from this sequence to any translated
287    * sequence
288    */
 
289  328 toggle public boolean involvesSequence(SequenceI seq)
290    {
291  328 return getAaForDnaSeq(seq) != null || getDnaForAaSeq(seq) != null;
292    }
293   
294    /**
295    * Add search results for regions in other sequences that translate or are
296    * translated from a particular position in seq
297    *
298    * @param seq
299    * @param index
300    * position in seq
301    * @param results
302    * where highlighted regions go
303    */
 
304  113 toggle public void markMappedRegion(SequenceI seq, int index,
305    SearchResultsI results)
306    {
307  113 int[] codon;
308  113 SequenceI ds = seq.getDatasetSequence();
309  113 for (SequenceToSequenceMapping ssm : mappings)
310    {
311  257 if (ssm.fromSeq == seq || ssm.fromSeq == ds)
312    {
313  54 codon = ssm.mapping.map.locateInTo(index, index);
314  54 if (codon != null)
315    {
316  90 for (int i = 0; i < codon.length; i += 2)
317    {
318  45 results.addResult(ssm.mapping.to, codon[i], codon[i + 1]);
319    }
320    }
321    }
322  203 else if (ssm.mapping.to == seq || ssm.mapping.to == ds)
323    {
324    {
325  59 codon = ssm.mapping.map.locateInFrom(index, index);
326  59 if (codon != null)
327    {
328  133 for (int i = 0; i < codon.length; i += 2)
329    {
330  74 results.addResult(ssm.fromSeq, codon[i], codon[i + 1]);
331    }
332    }
333    }
334    }
335    }
336    }
337   
338    /**
339    * Returns the DNA codon positions (base 1) for the given position (base 1) in
340    * a mapped protein sequence, or null if no mapping is found.
341    *
342    * Intended for use in aligning cDNA to match aligned protein. Only the first
343    * mapping found is returned, so not suitable for use if multiple protein
344    * sequences are mapped to the same cDNA (but aligning cDNA as protein is
345    * ill-defined for this case anyway).
346    *
347    * @param seq
348    * the DNA dataset sequence
349    * @param aaPos
350    * residue position (base 1) in a protein sequence
351    * @return
352    */
 
353  0 toggle public int[] getDnaPosition(SequenceI seq, int aaPos)
354    {
355    /*
356    * Adapted from markMappedRegion().
357    */
358  0 MapList ml = null;
359  0 int i = 0;
360  0 for (SequenceToSequenceMapping ssm : mappings)
361    {
362  0 if (ssm.fromSeq == seq)
363    {
364  0 ml = getdnaToProt()[i];
365  0 break;
366    }
367  0 i++;
368    }
369  0 return ml == null ? null : ml.locateInFrom(aaPos, aaPos);
370    }
371   
372    /**
373    * Convenience method to return the first aligned sequence in the given
374    * alignment whose dataset has a mapping with the given (aligned or dataset)
375    * sequence.
376    *
377    * @param seq
378    *
379    * @param al
380    * @return
381    */
 
382  31 toggle public SequenceI findAlignedSequence(SequenceI seq, AlignmentI al)
383    {
384    /*
385    * Search mapped protein ('to') sequences first.
386    */
387  31 for (SequenceToSequenceMapping ssm : mappings)
388    {
389  43 if (ssm.fromSeq == seq || ssm.fromSeq == seq.getDatasetSequence())
390    {
391  21 for (SequenceI sourceAligned : al.getSequences())
392    {
393  28 if (ssm.mapping.to == sourceAligned.getDatasetSequence()
394    || ssm.mapping.to == sourceAligned)
395    {
396  17 return sourceAligned;
397    }
398    }
399    }
400    }
401   
402    /*
403    * Then try mapped dna sequences.
404    */
405  14 for (SequenceToSequenceMapping ssm : mappings)
406    {
407  15 if (ssm.mapping.to == seq
408    || ssm.mapping.to == seq.getDatasetSequence())
409    {
410  9 for (SequenceI sourceAligned : al.getSequences())
411    {
412  11 if (ssm.fromSeq == sourceAligned.getDatasetSequence())
413    {
414  9 return sourceAligned;
415    }
416    }
417    }
418    }
419   
420  5 return null;
421    }
422   
423    /**
424    * Returns the region in the target sequence's dataset that is mapped to the
425    * given position (base 1) in the query sequence's dataset. The region is a
426    * set of start/end position pairs.
427    *
428    * @param target
429    * @param query
430    * @param queryPos
431    * @return
432    */
 
433  157 toggle public int[] getMappedRegion(SequenceI target, SequenceI query,
434    int queryPos)
435    {
436  157 SequenceI targetDs = target.getDatasetSequence() == null ? target
437    : target.getDatasetSequence();
438  157 SequenceI queryDs = query.getDatasetSequence() == null ? query
439    : query.getDatasetSequence();
440  157 if (targetDs == null || queryDs == null /*|| dnaToProt == null*/)
441    {
442  0 return null;
443    }
444  157 for (SequenceToSequenceMapping ssm : mappings)
445    {
446    /*
447    * try mapping from target to query
448    */
449  167 if (ssm.fromSeq == targetDs && ssm.mapping.to == queryDs)
450    {
451  40 int[] codon = ssm.mapping.map.locateInFrom(queryPos, queryPos);
452  40 if (codon != null)
453    {
454  36 return codon;
455    }
456    }
457    /*
458    * else try mapping from query to target
459    */
460  127 else if (ssm.fromSeq == queryDs && ssm.mapping.to == targetDs)
461    {
462  115 int[] codon = ssm.mapping.map.locateInTo(queryPos, queryPos);
463  115 if (codon != null)
464    {
465  23 return codon;
466    }
467    }
468    }
469  98 return null;
470    }
471   
472    /**
473    * Returns the mapped DNA codons for the given position in a protein sequence,
474    * or null if no mapping is found. Returns a list of (e.g.) ['g', 'c', 't']
475    * codons. There may be more than one codon mapped to the protein if (for
476    * example), there are mappings to cDNA variants.
477    *
478    * @param protein
479    * the peptide dataset sequence
480    * @param aaPos
481    * residue position (base 1) in the peptide sequence
482    * @return
483    */
 
484  53 toggle public List<char[]> getMappedCodons(SequenceI protein, int aaPos)
485    {
486  53 MapList ml = null;
487  53 SequenceI dnaSeq = null;
488  53 List<char[]> result = new ArrayList<char[]>();
489   
490  53 for (SequenceToSequenceMapping ssm : mappings)
491    {
492  55 if (ssm.mapping.to == protein
493    && ssm.mapping.getMap().getFromRatio() == 3)
494    {
495  29 ml = ssm.mapping.map;
496  29 dnaSeq = ssm.fromSeq;
497   
498  29 int[] codonPos = ml.locateInFrom(aaPos, aaPos);
499  29 if (codonPos == null)
500    {
501  17 return null;
502    }
503   
504    /*
505    * Read off the mapped nucleotides (converting to position base 0)
506    */
507  12 codonPos = MappingUtils.flattenRanges(codonPos);
508  12 int start = dnaSeq.getStart();
509  12 char c1 = dnaSeq.getCharAt(codonPos[0] - start);
510  12 char c2 = dnaSeq.getCharAt(codonPos[1] - start);
511  12 char c3 = dnaSeq.getCharAt(codonPos[2] - start);
512  12 result.add(new char[] { c1, c2, c3 });
513    }
514    }
515  36 return result.isEmpty() ? null : result;
516    }
517   
518    /**
519    * Returns any mappings found which are from the given sequence, and to
520    * distinct sequences.
521    *
522    * @param seq
523    * @return
524    */
 
525  13 toggle public List<Mapping> getMappingsFromSequence(SequenceI seq)
526    {
527  13 List<Mapping> result = new ArrayList<Mapping>();
528  13 List<SequenceI> related = new ArrayList<SequenceI>();
529  13 SequenceI seqDs = seq.getDatasetSequence();
530  13 seqDs = seqDs != null ? seqDs : seq;
531   
532  13 for (SequenceToSequenceMapping ssm : mappings)
533    {
534  15 final Mapping mapping = ssm.mapping;
535  15 if (ssm.fromSeq == seqDs)
536    {
537  15 if (!related.contains(mapping.to))
538    {
539  15 result.add(mapping);
540  15 related.add(mapping.to);
541    }
542    }
543    }
544  13 return result;
545    }
546   
547    /**
548    * Test whether the given sequence is substitutable for one or more dummy
549    * sequences in this mapping
550    *
551    * @param map
552    * @param seq
553    * @return
554    */
 
555  7 toggle public boolean isRealisableWith(SequenceI seq)
556    {
557  7 return realiseWith(seq, false) > 0;
558    }
559   
560    /**
561    * Replace any matchable mapped dummy sequences with the given real one.
562    * Returns the count of sequence mappings instantiated.
563    *
564    * @param seq
565    * @return
566    */
 
567  2 toggle public int realiseWith(SequenceI seq)
568    {
569  2 return realiseWith(seq, true);
570    }
571   
572    /**
573    * Returns the number of mapped dummy sequences that could be replaced with
574    * the given real sequence.
575    *
576    * @param seq
577    * a dataset sequence
578    * @param doUpdate
579    * if true, performs replacements, else only counts
580    * @return
581    */
 
582  9 toggle protected int realiseWith(SequenceI seq, boolean doUpdate)
583    {
584  9 SequenceI ds = seq.getDatasetSequence() != null
585    ? seq.getDatasetSequence()
586    : seq;
587  9 int count = 0;
588   
589    /*
590    * check for replaceable DNA ('map from') sequences
591    */
592  9 for (SequenceToSequenceMapping ssm : mappings)
593    {
594  10 SequenceI dna = ssm.fromSeq;
595  10 if (dna instanceof SequenceDummy
596    && dna.getName().equals(ds.getName()))
597    {
598  8 Mapping mapping = ssm.mapping;
599  8 int mapStart = mapping.getMap().getFromLowest();
600  8 int mapEnd = mapping.getMap().getFromHighest();
601  8 boolean mappable = couldRealiseSequence(dna, ds, mapStart, mapEnd);
602  8 if (mappable)
603    {
604  6 count++;
605  6 if (doUpdate)
606    {
607    // TODO: new method ? ds.realise(dna);
608    // might want to copy database refs as well
609  3 ds.setSequenceFeatures(dna.getSequenceFeatures());
610    // dnaSeqs[i] = ds;
611  3 ssm.fromSeq = ds;
612  3 System.out.println("Realised mapped sequence " + ds.getName());
613    }
614    }
615    }
616   
617    /*
618    * check for replaceable protein ('map to') sequences
619    */
620  10 Mapping mapping = ssm.mapping;
621  10 SequenceI prot = mapping.getTo();
622  10 int mapStart = mapping.getMap().getToLowest();
623  10 int mapEnd = mapping.getMap().getToHighest();
624  10 boolean mappable = couldRealiseSequence(prot, ds, mapStart, mapEnd);
625  10 if (mappable)
626    {
627  0 count++;
628  0 if (doUpdate)
629    {
630    // TODO: new method ? ds.realise(dna);
631    // might want to copy database refs as well
632  0 ds.setSequenceFeatures(dna.getSequenceFeatures());
633  0 ssm.mapping.setTo(ds);
634    }
635    }
636    }
637  9 return count;
638    }
639   
640    /**
641    * Helper method to test whether a 'real' sequence could replace a 'dummy'
642    * sequence in the map. The criteria are that they have the same name, and
643    * that the mapped region overlaps the candidate sequence.
644    *
645    * @param existing
646    * @param replacement
647    * @param mapStart
648    * @param mapEnd
649    * @return
650    */
 
651  28 toggle protected static boolean couldRealiseSequence(SequenceI existing,
652    SequenceI replacement, int mapStart, int mapEnd)
653    {
654  28 if (existing instanceof SequenceDummy
655    && !(replacement instanceof SequenceDummy)
656    && existing.getName().equals(replacement.getName()))
657    {
658  13 int start = replacement.getStart();
659  13 int end = replacement.getEnd();
660  13 boolean mappingOverlapsSequence = (mapStart >= start
661    && mapStart <= end) || (mapEnd >= start && mapEnd <= end);
662  13 if (mappingOverlapsSequence)
663    {
664  9 return true;
665    }
666    }
667  19 return false;
668    }
669   
670    /**
671    * Change any mapping to the given sequence to be to its dataset sequence
672    * instead. For use when mappings are created before their referenced
673    * sequences are instantiated, for example when parsing GFF data.
674    *
675    * @param seq
676    */
 
677  8 toggle public void updateToDataset(SequenceI seq)
678    {
679  8 if (seq == null || seq.getDatasetSequence() == null)
680    {
681  0 return;
682    }
683  8 SequenceI ds = seq.getDatasetSequence();
684   
685  8 for (SequenceToSequenceMapping ssm : mappings)
686    /*
687    * 'from' sequences
688    */
689    {
690  8 if (ssm.fromSeq == seq)
691    {
692  4 ssm.fromSeq = ds;
693    }
694   
695    /*
696    * 'to' sequences
697    */
698  8 if (ssm.mapping.to == seq)
699    {
700  4 ssm.mapping.to = ds;
701    }
702    }
703    }
704   
705    /**
706    * Answers true if this object contains no mappings
707    *
708    * @return
709    */
 
710  6 toggle public boolean isEmpty()
711    {
712  6 return mappings.isEmpty();
713    }
714   
715    /**
716    * Method for debug / inspection purposes only, may change in future
717    */
 
718  0 toggle @Override
719    public String toString()
720    {
721  0 return mappings == null ? "null" : mappings.toString();
722    }
723   
724    /**
725    * Returns the first mapping found that is between 'fromSeq' and 'toSeq', or
726    * null if none found
727    *
728    * @param fromSeq
729    * aligned or dataset sequence
730    * @param toSeq
731    * aligned or dataset sequence
732    * @return
733    */
 
734  9 toggle public Mapping getMappingBetween(SequenceI fromSeq, SequenceI toSeq)
735    {
736  9 SequenceI dssFrom = fromSeq.getDatasetSequence() == null ? fromSeq
737    : fromSeq.getDatasetSequence();
738  9 SequenceI dssTo = toSeq.getDatasetSequence() == null ? toSeq
739    : toSeq.getDatasetSequence();
740   
741  9 for (SequenceToSequenceMapping mapping : mappings)
742    {
743  12 SequenceI from = mapping.fromSeq;
744  12 SequenceI to = mapping.mapping.to;
745  12 if ((from == dssFrom && to == dssTo)
746    || (from == dssTo && to == dssFrom))
747    {
748  9 return mapping.mapping;
749    }
750    }
751  0 return null;
752    }
753   
754    /**
755    * Returns a hashcode derived from the list of sequence mappings
756    *
757    * @see SequenceToSequenceMapping#hashCode()
758    * @see AbstractList#hashCode()
759    */
 
760  0 toggle @Override
761    public int hashCode()
762    {
763  0 return this.mappings.hashCode();
764    }
765   
766    /**
767    * Two AlignedCodonFrame objects are equal if they hold the same ordered list
768    * of mappings
769    *
770    * @see SequenceToSequenceMapping#
771    */
 
772  196 toggle @Override
773    public boolean equals(Object obj)
774    {
775  196 if (!(obj instanceof AlignedCodonFrame))
776    {
777  0 return false;
778    }
779  196 return this.mappings.equals(((AlignedCodonFrame) obj).mappings);
780    }
781   
 
782  28 toggle public List<SequenceToSequenceMapping> getMappings()
783    {
784  28 return mappings;
785    }
786    }