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