b01dd6c0c92b877b21298510ee13455439d2d6dd
[jalview.git] / src / jalview / datamodel / ContactMatrix.java
1 package jalview.datamodel;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.StringTokenizer;
6
7 import jalview.bin.Console;
8
9 public abstract class ContactMatrix extends GroupSetHolder
10         implements ContactMatrixI
11 {
12   /**
13    * are contacts reflexive ?
14    */
15   boolean symmetric = true;
16
17   public ContactMatrix(boolean symmetric)
18   {
19     this.symmetric = symmetric;
20   }
21
22   List<List<Float>> contacts = null;
23
24   int width = 0, numcontacts = 0;
25
26   float min = 0f, max = 0f;
27
28   public void addContact(int left, int right, float strength)
29   {
30     if (left < 0 || right < 0)
31     {
32       throw new Error(new RuntimeException(
33               "Cannot have negative indices for contact left=" + left
34                       + " right=" + right + " strength=" + strength));
35     }
36     if (symmetric)
37     {
38       if (left > right)
39       {
40         // swap
41         int r = right;
42         right = left;
43         left = r;
44       }
45     }
46     if (contacts == null)
47     {
48       // TODO: use sparse list for efficiency ?
49       contacts = new ArrayList<List<Float>>();
50     }
51     List<Float> clist = contacts.get(left);
52     if (clist == null)
53     {
54       clist = new ArrayList<Float>();
55       contacts.set(left, clist);
56     }
57     Float last = clist.set(right, strength);
58     // TODO: if last is non null, may need to recompute range
59     checkBounds(strength);
60     if (last == null)
61     {
62       numcontacts++;
63     }
64   }
65
66   private void checkBounds(float strength)
67   {
68     if (min > strength)
69     {
70       min = strength;
71     }
72     if (max < strength)
73     {
74       max = strength;
75     }
76   }
77
78   @Override
79   public ContactListI getContactList(final int column)
80   {
81     if (column < 0 || column >= width)
82     {
83       return null;
84     }
85
86     return new ContactListImpl(new ContactListProviderI()
87     {
88       int p = column;
89
90       @Override
91       public int getPosition()
92       {
93         return p;
94       }
95
96       @Override
97       public int getContactHeight()
98       {
99         return width;
100
101       }
102
103       @Override
104       public double getContactAt(int column)
105       {
106         Float cl = getFloatElementAt(column, p);
107         if (cl == null)
108         {
109           // return 0 not NaN ?
110           return Double.NaN;
111         }
112         return cl.doubleValue();
113       }
114     });
115   }
116
117   private Float getFloatElementAt(int column, int p)
118   {
119
120     List<Float> clist;
121     Float cl = null;
122     if (symmetric)
123     {
124       if (p < column)
125       {
126         clist = contacts.get(p);
127         cl = clist.get(column);
128       }
129       else
130       {
131         clist = contacts.get(column);
132         cl = clist.get(p);
133       }
134     }
135     else
136     {
137       clist = contacts.get(p);
138       cl = clist.get(column);
139     }
140     return cl;
141   }
142
143   @Override
144   public double getElementAt(int column, int row)
145   {
146     Float cl = getFloatElementAt(column, row);
147     if (cl != null)
148     {
149       return cl;
150     }
151     throw (new RuntimeException("Out of Bounds " + column + "," + row));
152   }
153
154   @Override
155   public float getMin()
156   {
157     return min;
158   }
159
160   @Override
161   public float getMax()
162   {
163     return max;
164   }
165
166   @Override
167   public String getAnnotLabel()
168   {
169     return "Contact Matrix";
170   }
171
172   @Override
173   public String getAnnotDescr()
174   {
175     return "Contact Matrix";
176   }
177
178   public static String contactToFloatString(ContactMatrixI cm)
179   {
180     StringBuilder sb = new StringBuilder();
181     for (int c = 0; c < cm.getWidth(); c++)
182     {
183       ContactListI cl = cm.getContactList(c);
184       long lastsb = -1;
185       if (cl != null)
186       {
187         for (int h = 0; h <= cl.getContactHeight(); h++)
188         {
189           if (sb.length() > 0)
190           {
191             if (sb.length() - lastsb > 320)
192             {
193               // newline
194               sb.append('\n');
195               lastsb = sb.length();
196             }
197             else
198             {
199               sb.append('\t');
200             }
201           }
202           sb.append(cl.getContactAt(h));
203         }
204       }
205     }
206     return sb.toString();
207   }
208
209   public static float[][] fromFloatStringToContacts(String values, int cols,
210           int rows)
211   {
212     float[][] vals = new float[cols][rows];
213     StringTokenizer tabsep = new StringTokenizer(values, "" + '\t' + '\n');
214     int c = 0, r = 0;
215     while (tabsep.hasMoreTokens())
216     {
217       double elem = Double.valueOf(tabsep.nextToken());
218       vals[c][r++] = (float) elem;
219       if (r >= vals[c].length)
220       {
221         r = 0;
222         c++;
223       }
224       if (c >= vals.length)
225       {
226         break;
227       }
228     }
229     if (tabsep.hasMoreElements())
230     {
231       Console.warn(
232               "Ignoring additional elements for Float string to contact matrix parsing.");
233     }
234     return vals;
235   }
236 }