Clean-up, refactoring, commenting. Parameters file containts only options since Jalvi...
[jabaws.git] / datamodel / compbio / data / sequence / Score.java
1 /* Copyright (c) 2011 Peter Troshin\r
2  *  \r
3  *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 2.0     \r
4  * \r
5  *  This library is free software; you can redistribute it and/or modify it under the terms of the\r
6  *  Apache License version 2 as published by the Apache Software Foundation\r
7  * \r
8  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\r
9  *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache \r
10  *  License for more details.\r
11  * \r
12  *  A copy of the license is in apache_license.txt. It is also available here:\r
13  * @see: http://www.apache.org/licenses/LICENSE-2.0.txt\r
14  * \r
15  * Any republication or derived work distributed in source code form\r
16  * must include this copyright and license notice.\r
17  */\r
18 package compbio.data.sequence;\r
19 \r
20 import java.io.IOException;\r
21 import java.io.Writer;\r
22 import java.text.NumberFormat;\r
23 import java.util.ArrayList;\r
24 import java.util.Iterator;\r
25 import java.util.Locale;\r
26 import java.util.TreeSet;\r
27 \r
28 import javax.xml.bind.annotation.XmlAccessType;\r
29 import javax.xml.bind.annotation.XmlAccessorType;\r
30 \r
31 import compbio.util.annotation.Immutable;\r
32 \r
33 /**\r
34  * A value class for AACon annotation results storage. The objects of this type\r
35  * are immutable\r
36  * \r
37  * @author pvtroshin\r
38  * \r
39  */\r
40 @XmlAccessorType(XmlAccessType.FIELD)\r
41 @Immutable\r
42 public class Score implements Comparable<Score> {\r
43 \r
44         static final NumberFormat NUMBER_FORMAT = NumberFormat\r
45                         .getNumberInstance(Locale.UK);\r
46         static {\r
47                 NUMBER_FORMAT.setGroupingUsed(false);\r
48                 NUMBER_FORMAT.setMaximumFractionDigits(3);\r
49         }\r
50         // This should be Enum<?> but JAXB cannot serialize it.\r
51         private final String method;\r
52 \r
53         private TreeSet<Range> ranges = new TreeSet<Range>();\r
54 \r
55         private ArrayList<Float> scores = new ArrayList<Float>(0);\r
56 \r
57         private Score() {\r
58                 // JaXB default constructor\r
59                 method = "";\r
60         }\r
61 \r
62         /**\r
63          * Instantiate the Score\r
64          * \r
65          * @param method\r
66          *            the ConservationMethod with which {@code scores} were\r
67          *            calculated\r
68          * @param scores\r
69          *            the actual conservation values for each column of the\r
70          *            alignment\r
71          */\r
72         public Score(Enum<?> method, ArrayList<Float> scores) {\r
73                 this.method = method.toString();\r
74                 this.scores = new ArrayList<Float>(scores);\r
75         }\r
76 \r
77         /**\r
78          * @param method\r
79          *            the ConservationMethod with which {@code scores} were\r
80          *            calculated\r
81          * @param scores\r
82          *            the actual conservation values for each column of the\r
83          *            alignment\r
84          * @param ranges\r
85          *            The set of ranges i.e. parts of the sequence with specific\r
86          *            function, usually can be calculated based on scores\r
87          */\r
88         public Score(Enum<?> method, ArrayList<Float> scores, TreeSet<Range> ranges) {\r
89                 this.method = method.toString();\r
90                 this.ranges = ranges;\r
91                 this.scores = scores;\r
92         }\r
93 \r
94         public Score(Enum<?> method, TreeSet<Range> ranges) {\r
95                 this.method = method.toString();\r
96                 this.ranges = ranges;\r
97         }\r
98 \r
99         public Score(Enum<?> method, float[] scores) {\r
100                 this.method = method.toString();\r
101                 this.scores = toList(scores);\r
102         }\r
103 \r
104         private ArrayList<Float> toList(float[] values) {\r
105                 ArrayList<Float> vlist = new ArrayList<Float>();\r
106                 for (float v : values) {\r
107                         vlist.add(new Float(v));\r
108                 }\r
109                 return vlist;\r
110         }\r
111         /**\r
112          * Returns the ConservationMethod\r
113          * \r
114          * @return the ConservationMethod\r
115          */\r
116         public String getMethod() {\r
117                 return method;\r
118         }\r
119 \r
120         /**\r
121          * The column scores for the alignment\r
122          * \r
123          * @return the column scores for the alignment\r
124          */\r
125         public ArrayList<Float> getScores() {\r
126                 return scores;\r
127         }\r
128 \r
129         /**\r
130          * Return Ranges if any Collections.EMPTY_SET otherwise\r
131          * \r
132          * @return ordered set of Range\r
133          */\r
134         public TreeSet<Range> getRanges() {\r
135                 return ranges;\r
136         }\r
137 \r
138         public void setRanges(TreeSet<Range> ranges) {\r
139                 this.ranges = ranges;\r
140         }\r
141 \r
142         @Override\r
143         public String toString() {\r
144                 return "Score [method=" + method + ", ranges=" + ranges + ", scores="\r
145                                 + scores + "]";\r
146         }\r
147 \r
148         @Override\r
149         public int hashCode() {\r
150                 final int prime = 7;\r
151                 int result = 1;\r
152                 result = prime * result + ((method == null) ? 0 : method.hashCode());\r
153                 result = prime * result + ((ranges == null) ? 0 : ranges.hashCode());\r
154                 result = prime * result + ((scores == null) ? 0 : scores.hashCode());\r
155                 return result;\r
156         }\r
157 \r
158         @Override\r
159         public boolean equals(Object obj) {\r
160                 if (this == obj)\r
161                         return true;\r
162                 if (obj == null)\r
163                         return false;\r
164                 if (getClass() != obj.getClass())\r
165                         return false;\r
166                 Score other = (Score) obj;\r
167                 if (method == null) {\r
168                         if (other.method != null)\r
169                                 return false;\r
170                 } else if (!method.equals(other.method))\r
171                         return false;\r
172                 if (ranges == null) {\r
173                         if (other.ranges != null)\r
174                                 return false;\r
175                 } else if (!ranges.equals(other.ranges))\r
176                         return false;\r
177                 if (scores == null) {\r
178                         if (other.scores != null)\r
179                                 return false;\r
180                 } else if (!scores.equals(other.scores))\r
181                         return false;\r
182                 return true;\r
183         }\r
184 \r
185         /**\r
186          * Outputs the List of Score objects into the Output stream. The output\r
187          * format is as follows:\r
188          * \r
189          * <pre>\r
190          * {@code\r
191          * #MethodName [comma separated list of ranges] <space separated list of values>\r
192          *        \r
193          * For example:\r
194          *       \r
195          * #KABAT 0.2 0.3 0.2 0 0.645 0.333 1 1 0 0\r
196          * #SMERFS 0.645 0.333 1 1 0 0 0.2 0.3 0.2 0\r
197          * #COILS 22-33, 44-56 0.121 3.212\r
198          * }\r
199          * </pre>\r
200          * \r
201          * The maximum precision for values is 3 digits, but can be less.\r
202          * \r
203          * @param scores\r
204          *            the list of scores to output\r
205          * @param writer\r
206          * @throws IOException\r
207          *             if the OutputStream cannot be written into\r
208          * @throws NullPointerException\r
209          *             if the output stream is null\r
210          */\r
211         public static void write(TreeSet<Score> scores, Writer writer)\r
212                         throws IOException {\r
213                 if (writer == null) {\r
214                         throw new NullPointerException("Writer must be provided!");\r
215                 }\r
216                 for (Score score : scores) {\r
217                         writer.write("#" + score.method);\r
218                         int count = score.ranges.size();\r
219                         for (Range range : score.ranges) {\r
220                                 count--;\r
221                                 writer.write(" "+range.toString());\r
222                                 if (count != 0) {\r
223                                         writer.write(",");\r
224                                 }\r
225                         }\r
226                         for (Float scoreVal : score.scores) {\r
227                                 writer.write(" "+NUMBER_FORMAT.format(scoreVal));\r
228                         }\r
229                         writer.write("\n");\r
230                         writer.flush();\r
231                 }\r
232                 writer.flush();\r
233         }\r
234 \r
235         // Old compareTo method\r
236 //      @Override\r
237 //      public int compareTo(Score o) {\r
238 //              return this.method.compareTo(o.method);\r
239 //      }\r
240         \r
241         /* daniel messed with this method. While preserving the original\r
242          * ordering when the method Enumerations are different, additional\r
243          * constraints have been added on how equal Score objects must be \r
244          * to be considered equal.\r
245          * \r
246          * It is necessary to distinguish Score objects by their ranges in order\r
247          * to use a Set of Score objects to represent the alifold.out information\r
248          * \r
249          * Distinguishing score objects by their Scores has the result of ordering\r
250          * the base pair contacts so into descending probability.\r
251          * \r
252          * Should this be in a new extended Score class?\r
253          */\r
254         \r
255         @Override\r
256         public int compareTo(Score o) {\r
257                 if (this.method.compareTo(o.method) != 0) {\r
258                         return this.method.compareTo(o.method);\r
259                 }\r
260                 int pass;\r
261                 pass = new Integer(this.scores.size()).compareTo(\r
262                                 new Integer(o.scores.size())); \r
263                 if (pass != 0) return pass;\r
264                 for (int i = 0; i < this.scores.size(); i++) {\r
265                         pass = this.scores.get(i).compareTo(o.scores.get(i));\r
266                         if (pass != 0) {\r
267                                 return pass*-1; // descending order\r
268                         }\r
269                 }\r
270                 \r
271                 pass = new Integer(this.ranges.size()).compareTo(\r
272                                 new Integer(o.ranges.size())); \r
273                 if (pass != 0) return pass; \r
274                 Iterator<Range> thisRange = this.ranges.iterator();\r
275                 Iterator<Range> oRange = o.ranges.iterator();\r
276                 for (int i = 0; i < this.ranges.size(); i++) {\r
277                         Range tR = thisRange.next();\r
278                         Range oR = oRange.next();\r
279                         \r
280                         if (tR.compareTo(oR) != 0) {\r
281                                 return tR.compareTo(oR);\r
282                         }\r
283                 }\r
284                 \r
285                 return 0;       \r
286         }\r
287 }\r