/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.datamodel; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import jalview.bin.Console; public abstract class ContactMatrix extends GroupSetHolder implements ContactMatrixI { /** * are contacts reflexive ? */ boolean symmetric = true; public ContactMatrix(boolean symmetric) { this.symmetric = symmetric; } List> contacts = null; int width = 0, numcontacts = 0; float min = 0f, max = 0f; public void addContact(int left, int right, float strength) { if (left < 0 || right < 0) { throw new Error(new RuntimeException( "Cannot have negative indices for contact left=" + left + " right=" + right + " strength=" + strength)); } if (symmetric) { if (left > right) { // swap int r = right; right = left; left = r; } } if (contacts == null) { // TODO: use sparse list for efficiency ? contacts = new ArrayList>(); } List clist = contacts.get(left); if (clist == null) { clist = new ArrayList(); contacts.set(left, clist); } Float last = clist.set(right, strength); // TODO: if last is non null, may need to recompute range checkBounds(strength); if (last == null) { numcontacts++; } } private void checkBounds(float strength) { if (min > strength) { min = strength; } if (max < strength) { max = strength; } } @Override public ContactListI getContactList(final int column) { if (column < 0 || column >= width) { return null; } return new ContactListImpl(new ContactListProviderI() { int p = column; @Override public int getPosition() { return p; } @Override public int getContactHeight() { return width; } @Override public double getContactAt(int column) { Float cl = getFloatElementAt(column, p); if (cl == null) { // return 0 not NaN ? return Double.NaN; } return cl.doubleValue(); } }); } private Float getFloatElementAt(int column, int p) { List clist; Float cl = null; if (symmetric) { if (p < column) { clist = contacts.get(p); cl = clist.get(column); } else { clist = contacts.get(column); cl = clist.get(p); } } else { clist = contacts.get(p); cl = clist.get(column); } return cl; } @Override public double getElementAt(int column, int row) { Float cl = getFloatElementAt(column, row); if (cl != null) { return cl; } throw (new RuntimeException("Out of Bounds " + column + "," + row)); } @Override public float getMin() { return min; } @Override public float getMax() { return max; } @Override public String getAnnotLabel() { return "Contact Matrix"; } @Override public String getAnnotDescr() { return "Contact Matrix"; } public static String contactToFloatString(ContactMatrixI cm) { StringBuilder sb = new StringBuilder(); for (int c = 0; c < cm.getWidth(); c++) { ContactListI cl = cm.getContactList(c); long lastsb = -1; if (cl != null) { for (int h = 0; h <= cl.getContactHeight(); h++) { if (sb.length() > 0) { if (sb.length() - lastsb > 320) { // newline sb.append('\n'); lastsb = sb.length(); } else { sb.append('\t'); } } sb.append(cl.getContactAt(h)); } } } return sb.toString(); } public static float[][] fromFloatStringToContacts(String values, int cols, int rows) { float[][] vals = new float[cols][rows]; StringTokenizer tabsep = new StringTokenizer(values, "" + '\t' + '\n'); int c = 0, r = 0; while (tabsep.hasMoreTokens()) { double elem = Double.valueOf(tabsep.nextToken()); vals[c][r++] = (float) elem; if (r >= vals[c].length) { r = 0; c++; } if (c >= vals.length) { break; } } if (tabsep.hasMoreElements()) { Console.warn( "Ignoring additional elements for Float string to contact matrix parsing."); } return vals; } }