/*
* 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.milaboratory.core.sequence.Alphabet;
import com.milaboratory.core.sequence.Wildcard;
import gnu.trove.set.hash.TByteHashSet;
import java.util.Arrays;
/**
* ScoringUtils - class which contains some useful helpers used in scoring systems
*/
public final class ScoringUtils {
private ScoringUtils() {
}
/**
* Returns simple substitution matrix
*
* @param match match score
* @param mismatch mismatch score
* @param alphabet alphabet
* @return simple substitution matrix
*/
public static int[] getSymmetricMatrix(int match, int mismatch, Alphabet<?> alphabet) {
int codes = alphabet.size();
int[] matrix = new int[codes * codes];
Arrays.fill(matrix, mismatch);
for (int i = 0; i < codes; ++i)
matrix[i + codes * i] = match;
return fillWildcardScores(matrix, alphabet);
}
public static int[] setMismatchScore(Alphabet<?> alphabet, int[] matrix, int mismatch) {
int size = (int) Math.round(Math.sqrt(matrix.length));
if (size * size != matrix.length || alphabet.size() != size)
throw new IllegalArgumentException();
int[] result = matrix.clone();
int basicSize = alphabet.basicSize();
for (int i = 0; i < basicSize; ++i)
for (int j = 0; j < basicSize; ++j)
if (i != j)
result[i + size * j] = mismatch;
return fillWildcardScores(result, alphabet);
}
public static int[] setMatchScore(Alphabet<?> alphabet, int[] matrix, int match) {
int size = (int) Math.round(Math.sqrt(matrix.length));
if (size * size != matrix.length || alphabet.size() != size)
throw new IllegalArgumentException();
int[] result = matrix.clone();
int basicSize = alphabet.basicSize();
for (int i = 0; i < basicSize; ++i)
result[i + size * i] = match;
return fillWildcardScores(result, alphabet);
}
/**
* Fills up scores for wildcards by averaging scores for all their matching scores combinations.
*
* @param matrix initial matrix (will be modified in-place)
* @param alphabet alphabet
* @param exclude list of codes to exclude from this action
* @return the same reference as matrix
*/
public static int[] fillWildcardScores(int[] matrix, Alphabet<?> alphabet, byte... exclude) {
int alSize = alphabet.size();
if (matrix.length != alSize * alSize)
throw new IllegalArgumentException("Wrong matrix size.");
TByteHashSet excludeSet = new TByteHashSet(exclude);
for (Wildcard wc1 : alphabet.getAllWildcards())
for (Wildcard wc2 : alphabet.getAllWildcards()) {
if ((wc1.isBasic() || excludeSet.contains(wc1.getCode())) && (wc2.isBasic() || excludeSet.contains(wc2.getCode())))
continue;
int sumScore = 0;
for (int i = 0; i < wc1.basicSize(); i++)
for (int j = 0; j < wc2.basicSize(); j++) {
sumScore += matrix[wc1.getMatchingCode(i) + wc2.getMatchingCode(j) * alSize];
}
sumScore /= wc1.basicSize() * wc2.basicSize();
matrix[wc1.getCode() + wc2.getCode() * alSize] = sumScore;
}
return matrix;
}
///**
// * Returns true if scores for wildcard symbols is the same as {@link #fillWildcardScores(int[], Alphabet, byte...)}
// * with no exclude symbols would produce.
// *
// * @param matrix matrix to test
// * @return {@literal true} if scores for wildcards are the same as would be calculated automatically by {@link
// * #fillWildcardScores(int[], Alphabet, byte...)} method
// */
//public static boolean isDefaultWildcardScores(int[] matrix, Alphabet<?> alphabet) {
// int alSize = alphabet.size();
//
// if (matrix.length != alSize * alSize)
// throw new IllegalArgumentException("Wrong matrix size.");
//
// for (Wildcard wc1 : alphabet.getAllWildcards())
// for (Wildcard wc2 : alphabet.getAllWildcards()) {
// if (wc1.isBasic())
// continue;
// int sumScore = 0;
// for (int i = 0; i < wc1.count(); i++)
// for (int j = 0; j < wc2.count(); j++) {
// sumScore += matrix[wc1.getMatchingCode(i) + wc2.getMatchingCode(j) * alSize];
// }
// sumScore /= wc1.count() * wc2.count();
//
// if (matrix[wc1.getCode() + wc2.getCode() * alSize] != sumScore)
// return false;
// }
//
// return true;
//}
}