/* * Copyright 2015 MiLaboratory.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.milaboratory.core.alignment; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.milaboratory.core.sequence.AminoAcidSequence; import com.milaboratory.util.IntArrayList; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import static com.milaboratory.core.sequence.AminoAcidAlphabet.INCOMPLETE_CODON; import static com.milaboratory.core.sequence.AminoAcidAlphabet.STOP; final class ScoringMatrixIO { public static final class Deserializer extends JsonDeserializer<SubstitutionMatrix> { @Override public SubstitutionMatrix deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { String strValue = jp.readValueAs(String.class); strValue = strValue.replaceAll("\\s", "").toLowerCase(); if (strValue.startsWith("raw(")) { if (!strValue.endsWith(")")) throw new IOException("Not balanced brackets in : " + strValue); strValue = strValue.substring(4, strValue.length() - 1); String split[] = strValue.split(","); int[] values = new int[split.length]; for (int i = 0; i < split.length; ++i) values[i] = Integer.parseInt(split[i], 10); return new SubstitutionMatrix(values); } if (strValue.startsWith("simple(")) { if (!strValue.endsWith(")")) throw new IOException("Not balanced brackets in : " + strValue); strValue = strValue.substring(7, strValue.length() - 1); String split[] = strValue.split(","); int match = Integer.MIN_VALUE, mismatch = Integer.MIN_VALUE; for (int i = 0; i < split.length; ++i) { if (split[i].startsWith("match=")) match = Integer.parseInt(split[i].substring(6), 10); if (split[i].startsWith("mismatch=")) mismatch = Integer.parseInt(split[i].substring(9), 10); } if (match == Integer.MIN_VALUE) throw new IOException("Match value not set in : " + strValue); if (mismatch == Integer.MIN_VALUE) throw new IOException("Mismatch value not set in : " + strValue); return new SubstitutionMatrix(match, mismatch); } throw new IOException("Can't parse: " + strValue); } } public static final class Serializer extends JsonSerializer<SubstitutionMatrix> { @Override public void serialize(SubstitutionMatrix value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { if (value.data.length == 2) jgen.writeString("simple(match = " + value.data[0] + ", mismatch = " + value.data[1] + ")"); else { StringBuilder sb = new StringBuilder(); for (int i = 0; i < value.data.length; ++i) { sb.append(value.data[i]); sb.append(", "); } sb.delete(sb.length() - 2, sb.length()); jgen.writeString("raw(" + sb.toString() + ")"); } } } //public static final class Deserializer extends JsonDeserializer<int[]> { // @Override // public int[] deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // String strValue = jp.readValueAs(String.class); // strValue = strValue.replaceAll("\\s", "").toLowerCase(); // // if (strValue.startsWith("raw(")) { // // if (!strValue.endsWith(")")) // throw new IOException("Not balanced brackets in : " + strValue); // // strValue = strValue.substring(4, strValue.length() - 1); // String split[] = strValue.split(","); // // int[] values = new int[split.length]; // for (int i = 0; i < split.length; ++i) // values[i] = Integer.parseInt(split[i], 10); // // return values; // } // // if (strValue.startsWith("simple(")) { // if (!strValue.endsWith(")")) // throw new IOException("Not balanced brackets in : " + strValue); // // strValue = strValue.substring(7, strValue.length() - 1); // // String split[] = strValue.split(","); // // int match = Integer.MIN_VALUE, mismatch = Integer.MIN_VALUE; // // for (int i = 0; i < split.length; ++i) { // if (split[i].startsWith("match=")) // match = Integer.parseInt(split[i].substring(6), 10); // if (split[i].startsWith("mismatch=")) // mismatch = Integer.parseInt(split[i].substring(9), 10); // } // // if (match == Integer.MIN_VALUE) // throw new IOException("Match value not set in : " + strValue); // // if (mismatch == Integer.MIN_VALUE) // throw new IOException("Mismatch value not set in : " + strValue); // // return new int[]{match, mismatch}; // } // // throw new IOException("Can't parse: " + strValue); // } //} // //public static final class Serializer extends JsonSerializer<int[]> { // @Override // public void serialize(int[] value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { // int size = (int) (Math.sqrt(value.length)); // // if (value.length != size * size) // throw new IOException("Wrong matrix size."); // // int diagonalValue = value[0]; // int otherValue = value[1]; // // boolean isSymmetric = true; // // for (int i = 0; i < size; ++i) // for (int j = 0; j < size; ++j) { // // if (i == j) // isSymmetric &= (value[size * i + j] == diagonalValue); // else // isSymmetric &= (value[size * i + j] == otherValue); // // if (!isSymmetric) // break; // } // // if (isSymmetric) // jgen.writeString("simple(match = " + diagonalValue + ", mismatch = " + otherValue + ")"); // else { // StringBuilder sb = new StringBuilder(); // for (int i = 0; i < value.length; ++i) { // sb.append(value[i]); // sb.append(", "); // } // sb.delete(sb.length() - 2, sb.length()); // jgen.writeString("raw(" + sb.toString() + ")"); // } // } //} /** * Reads BLAST AminoAcid substitution matrix from InputStream * * @param stream InputStream * @return BLAST AminoAcid substitution matrix * @throws java.io.IOException */ public static int[] readAABlastMatrix(InputStream stream) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(stream)); String line; //Creating stopValues array int[] stopValues = new int[]{STOP, INCOMPLETE_CODON}; //~AminoAcidAlphabet. IntArrayList mappings = new IntArrayList(30); int alSize = AminoAcidSequence.ALPHABET.size(); int[] matrix = new int[alSize * alSize]; Arrays.fill(matrix, Integer.MIN_VALUE); String[] cells; while ((line = br.readLine()) != null) { //Processing comment if (line.startsWith("#")) continue; //Processing header if (line.startsWith(" ")) { String[] letters = line.trim().split("\\s+"); for (int i = 0; i < letters.length; ++i) mappings.add(getAACode(letters[i])); continue; } //Processing line with values cells = line.trim().split("\\s+"); //Parsing letter in the first column for (int from : getVals(getAACode(cells[0]), stopValues)) { for (int i = 1; i < cells.length; ++i) for (int to : getVals(mappings.get(i - 1), stopValues)) matrix[from * alSize + to] = Integer.parseInt(cells[i]); } } // Filling gaps in matrix // ScoringUtils.fillWildcardScores(matrix, AminoAcidSequence.ALPHABET, X, INCOMPLETE_CODON); //Checking for matrix fullness for (int val : matrix) if (val == Integer.MIN_VALUE) throw new IllegalArgumentException("Some letters are missing in matrix."); return matrix; } private static int[] getVals(int ll, int[] stopValues) { if (ll == -1) return new int[0]; if (ll == -2) return stopValues; return new int[]{ll}; } /** * Returns AminoAcid code * * @param letter letter * @return code */ private static byte getAACode(String letter) { if (letter.length() != 1) throw new IllegalArgumentException(); char l = letter.charAt(0); if (l == '*' || l == '*') return -2; return AminoAcidSequence.ALPHABET.symbolToCode(l); } }