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