001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.core.alignment.matrices;
022
023import org.biojava.nbio.core.alignment.template.SubstitutionMatrix;
024import org.biojava.nbio.core.sequence.compound.AminoAcidCompound;
025import org.biojava.nbio.core.sequence.compound.AminoAcidCompoundSet;
026
027import java.io.BufferedReader;
028import java.io.IOException;
029import java.io.InputStream;
030import java.io.InputStreamReader;
031import java.util.ArrayList;
032import java.util.HashMap;
033import java.util.List;
034import java.util.Map;
035
036
037
038public class AAIndexFileParser {
039        int scale = -1;
040
041        Map<String,SubstitutionMatrix<AminoAcidCompound>> matrices;
042
043        ScaledSubstitutionMatrix currentMatrix;
044        String currentRows;
045        String currentCols;
046        int currentRowPos;
047        private short[][] matrix;
048        short max;
049        short min;
050        private List<AminoAcidCompound> rows, cols;
051        boolean inMatrix;
052        boolean symmetricMatrix ;
053
054        public AAIndexFileParser(){
055                matrices  = new HashMap<String, SubstitutionMatrix<AminoAcidCompound>>();
056        }
057
058        /** Parse an inputStream that points to an AAINDEX database file
059         *
060         * @param inputStream
061         * @throws IOException
062         */
063        public void parse(InputStream inputStream) throws IOException {
064
065                currentMatrix = null;
066                currentRows = "";
067                currentCols = "";
068                max = Short.MIN_VALUE;
069                min = Short.MAX_VALUE;
070                inMatrix = false;
071
072                BufferedReader buf = new BufferedReader (new InputStreamReader (inputStream));
073                String line = null;
074                line = buf.readLine();
075
076                while (  line != null ) {
077                        if ( line.startsWith("//")) {
078                                finalizeMatrix();
079                                inMatrix = false;
080
081                        } else if ( line.startsWith("H ")){
082                                // a new matrix!
083                                newMatrix(line);
084                        } else if ( line.startsWith("D ")) {
085                                currentMatrix.setDescription(line.substring(2));
086                        } else if ( line.startsWith("M ")) {
087                                initMatrix(line);
088                                inMatrix = true;
089                        } else if ( line.startsWith("  ")){
090                                if ( inMatrix)
091                                        processScores(line);
092                        }
093                        line = buf.readLine();
094                }
095        }
096
097        //  process a line such as >    -0.3     1.6     0.7     0.8    -2.6     3.0<
098        private void processScores(String line) {
099                String[] values = line.trim().split(" +");
100
101                // increment the current row we are talking about
102                currentRowPos++;
103
104                for ( int i =0 ; i < values.length ; i++){
105                        if ( values[i].endsWith(".")) {
106                                values[i] = values[i] + "0";
107                        }
108
109                        // special case: MEHP950101
110                        if (values[i].equals("-")) {
111                                values[i] = "0";
112                        }
113                        if ( scale == -1 ) {
114                                scale = determineScale(values[0]);
115                        }
116
117                        Float score = Float.parseFloat(values[i]);
118                        score = scale * score;
119
120                        Short s = (short) Math.round(score);
121                        matrix[currentRowPos][i] = s;
122
123                        if ( values.length < cols.size() || ( symmetricMatrix)){
124                                //System.out.println(values.length + " " + cols.size() + " " + currentRowPos + " " + i + " " +  line);
125                                matrix[i][currentRowPos] = s;
126                                symmetricMatrix = true;
127                        }
128                        if ( score > max)
129                                max = s;
130                        if ( score < min)
131                                min = s;
132                }
133        }
134
135        private int determineScale(String value) {
136                String[] spl = value.split("\\.");
137                if (spl.length <= 1)
138                        return 1;
139                String digits = spl[1];
140                return (int)Math.round(Math.pow(10, digits.length()));
141        }
142
143        // process a line of type >M rows = ARNDCQEGHILKMFPSTWYV, cols = ARNDCQEGHILKMFPSTWYV<
144        private void initMatrix(String line) {
145                String[] spl = line.split(" ");
146
147                // trim off the final , character
148                currentRows = spl[3].substring(0, spl[3].length()-1);
149                currentCols = spl[6];
150                currentRowPos = -1;
151
152                int nrRows = currentRows.length();
153                int nrCols = currentCols.length();
154
155                matrix = new short[nrRows][nrCols];
156
157                rows = new ArrayList<AminoAcidCompound>();
158                cols = new ArrayList<AminoAcidCompound>();
159
160                //System.out.println(">" + currentRows+"<");
161                AminoAcidCompoundSet compoundSet = AminoAcidCompoundSet.getAminoAcidCompoundSet();
162                for ( int i = 0 ; i < currentRows.length() ; i ++){
163                        char c = currentRows.charAt(i);
164                        AminoAcidCompound aa = compoundSet.getCompoundForString(String.valueOf(c));
165                        rows.add(aa);
166                }
167
168                for ( int i = 0 ; i < currentCols.length() ; i ++){
169                        char c = currentRows.charAt(i);
170                        AminoAcidCompound aa = compoundSet.getCompoundForString(String.valueOf(c));
171                        cols.add(aa);
172                }
173                currentMatrix.setScale(scale);
174        }
175
176
177        private void newMatrix(String line) {
178                symmetricMatrix = false;
179                scale = -1;
180
181                currentMatrix = new ScaledSubstitutionMatrix();
182                currentMatrix.setName(line.substring(2));
183
184
185                //System.out.println("new Matrix " + currentMatrix.getName());
186        }
187
188        //
189        private SubstitutionMatrix<AminoAcidCompound> finalizeMatrix() {
190
191                currentMatrix.setMatrix(matrix);
192                currentMatrix.setMax(max);
193                currentMatrix.setMin(min);
194                currentMatrix.setCols(cols);
195                currentMatrix.setRows(rows);
196                currentMatrix.setScale(scale);
197                matrices.put(currentMatrix.getName(), currentMatrix);
198
199                return currentMatrix;
200
201        }
202
203        public Map<String, SubstitutionMatrix<AminoAcidCompound>> getMatrices() {
204                return matrices;
205        }
206}