import scala.io.Source
import Array._
/**
* Created by Const.
*/
class Aligner(fileWithData: String) {
// Read file with data
val data = Source.fromFile(fileWithData).mkString.split("\n").toList
// Read alphabet from alphabet string
val alphabet = data(0).zipWithIndex.map{case (x: Char, i: Int) => (x, i)}.toMap
// Take N rows of (N, N)-matrix from readed data and preserve other data
val (mtxData, otherData) = (data.take(alphabet.size + 1).tail, data.drop(alphabet.size + 1))
// And make matrix from matrix rows (N strings represents N rows)
val mtx = mtxData.map(_.split(" ").map(_ toInt)).toArray
// Some debug print of error matrix
println("Error matrix")
for ((ch, idx) <- alphabet)
print(f"$ch%-5c")
println()
for ((row, idx) <- mtx.zipWithIndex) {
for (j <- row) {
print(f"$j%-5d")
}
println()
}
println()
// Take other data
val (gapScore, maxGaps, firstSeq, secondSeq) = otherData match {
case (score: String) :: (maxg: String) :: (fst: String) :: (scd: String) :: Nil => (score.toInt, maxg.toInt, fst, scd)
case _ => throw new IllegalArgumentException("Please check your input file.")
}
// Initialize Score Matrix
var scoreMatrix = ofDim[Int](secondSeq.length + 1, firstSeq.length + 1)
// Find index of maximum element in array
// And (optional) that is not contained in Excluded Indices Set
def indexOfLargest(array: Seq[Int], excIndices: Set[Int] = Set[Int]()): Int = {
val result = array.foldLeft(-1,Int.MinValue,0) {
case ((maxIndex, maxValue, currentIndex), currentValue) =>
if(currentValue > maxValue && !(excIndices contains currentIndex)) (currentIndex,currentValue,currentIndex+1)
else (maxIndex,maxValue,currentIndex+1)
}
result._1
}
def alignWithNiddleman(maximumGaps: Int = maxGaps) {
// Build Score Matrix
for (i <- 0 to secondSeq.length)
scoreMatrix(i)(0) = 0
for (j <- 0 to firstSeq.length)
scoreMatrix(0)(j) = 0
for (i <- scoreMatrix.indices if i > 0) {
for (j <- scoreMatrix(i).indices if j > 0) {
val matcher = scoreMatrix(i - 1)(j - 1) + mtx(alphabet(secondSeq(i - 1)))(alphabet(firstSeq(j - 1)))
val delete = scoreMatrix(i - 1)(j) + gapScore
val insert = scoreMatrix(i)(j - 1) + gapScore
scoreMatrix(i)(j) = List[Int](matcher, delete, insert, 0).max
}
}
// Some debug print pf Score Matrix
println("Score Matrix:")
for (row <- scoreMatrix) {
for (j <- row) {
printf("%-5d", j)
}
println()
}
val aligned = findProperAlignment()
println(aligned._1 mkString)
println(aligned._2 mkString)
}
def findProperAlignment(excludeSet: Set[Int] = Set[Int]()): (List[Char], List[Char]) = {
// Find optimal local alignment
var aligned = (List[Char](), List[Char]())
var i = scoreMatrix.size - 1
var idxOfMax = indexOfLargest(scoreMatrix(scoreMatrix.size - 1), excludeSet)
var j = idxOfMax
var gapCount = 0
for (k <- (firstSeq.length - 1) until j by -1) {
aligned = (firstSeq(k - 1) +: aligned._1, '+' +: aligned._2)
}
while (scoreMatrix(i)(j) != 0) {
val forward = scoreMatrix(i - 1)(j - 1)
val gapSecond = scoreMatrix(i - 1)(j)
val gapFirst = scoreMatrix(i)(j - 1)
(forward :: gapFirst :: gapSecond :: Nil).max match {
case x if forward == x => {
aligned = (firstSeq(j - 1) +: aligned._1, secondSeq(i - 1) +: aligned._2)
i -= 1
j -= 1
}
case x if gapFirst == x => {
aligned = (firstSeq(j - 1) +: aligned._1, '-' +: aligned._2)
j -= 1
gapCount += 1
}
case x if gapSecond == x => {
aligned = ('-' +: aligned._1, secondSeq(i - 1) +: aligned._2)
i -= 1
gapCount += 1
}
}
if (gapCount > maxGaps)
return findProperAlignment(excludeSet + idxOfMax)
}
if (i > 0) {
while (i > 0) {
aligned = ('+' +: aligned._1, secondSeq(i - 1) +: aligned._2)
i -= 1
}
}
if (j > 0) {
while (j > 0) {
aligned = (firstSeq(j - 1) +: aligned._1, '+' +: aligned._2)
j -= 1
}
}
aligned
}
}