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