
de.citec.tcs.alignment.StrictAlignmentFullAlgorithm Maven / Gradle / Ivy
/*
* TCS Alignment Toolbox
*
* Copyright (C) 2013-2015
* Benjamin Paaßen, Georg Zentgraf
* AG Theoretical Computer Science
* Centre of Excellence Cognitive Interaction Technology (CITEC)
* University of Bielefeld
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package de.citec.tcs.alignment;
import de.citec.tcs.alignment.comparators.OperationType;
import de.citec.tcs.alignment.sequence.Node;
import de.citec.tcs.alignment.sequence.Sequence;
import java.util.Stack;
/**
* This is an implementation of the Needleman-Wunsch-Algorithm for sequence
* alignment. It returns an optimal alignment path. The scoring scheme is
* equivalent to the StrictAlignmentScoreAlgorithm.
*
* @author Benjamin Paassen - bpaassen(at)techfak.uni-bielefeld.de
*/
public class StrictAlignmentFullAlgorithm
extends AbstractGapAlignmentAlgorithm {
/**
* This sets up an AlignmentAlgorithm instance according to the given
* specification.
*
* @param alignmentSpecification an AlignmentSpecification.
*/
public StrictAlignmentFullAlgorithm(AlignmentSpecification alignmentSpecification) {
super(alignmentSpecification, FullMatrixEntry.class, AlignmentPath.class);
}
/**
* {@inheritDoc }
*/
@Override
public FullMatrixEntry createInitial() {
return new FullMatrixEntry(0, 0, 0, null);
}
/**
* {@inheritDoc }
*/
@Override
public FullMatrixEntry createDelInitial(FullMatrixEntry delOld, int i, double delLocal) {
return new FullMatrixEntry(delOld.getScore() + delLocal, i, 0, delOld);
}
/**
* {@inheritDoc }
*/
@Override
public FullMatrixEntry createInsInitial(FullMatrixEntry insOld, int j, double insLocal) {
return new FullMatrixEntry(insOld.getScore() + insLocal, 0, j, insOld);
}
/**
* {@inheritDoc }
*/
@Override
public FullMatrixEntry createNewEntry(FullMatrixEntry delOld, FullMatrixEntry insOld,
FullMatrixEntry repOld,
int i, int j,
double delLocal, double insLocal, double repLocal) {
final double delTotal = delOld.getScore() + delLocal;
final double insTotal = insOld.getScore() + insLocal;
final double repTotal = repOld.getScore() + repLocal;
if (delTotal < insTotal) {
if (delTotal < repTotal) {
return new FullMatrixEntry(delTotal, i, j, delOld);
} else {
return new FullMatrixEntry(repTotal, i, j, repOld);
}
} else {
if (insTotal < repTotal) {
return new FullMatrixEntry(insTotal, i, j, insOld);
} else {
return new FullMatrixEntry(repTotal, i, j, repOld);
}
}
}
/**
* {@inheritDoc }
*/
public AlignmentPath transformToResult(FullMatrixEntry[][] alignmentMatrix, Sequence a,
Sequence b) {
final FullMatrixEntry last = alignmentMatrix[a.getNodes().size()][b.getNodes().size()];
/*
* In each step of the alignment we had a distance of 1 at most. Thus we
* can normalize the score to the range [0,1] if we just divide the raw
* score by the worst case, which would be to delete a entirely and
* insert b entirely => worst case score = m+n.
*/
final int normalization = Math.max(1, a.getNodes().size() + b.getNodes().size());
final double normalizedScore = last.getScore() / normalization;
//Now backtrace to reconstruct the path.
final AlignmentPath path = new AlignmentPath(getSpecification(), a, b,
normalizedScore);
final Stack ops = new Stack<>();
FullMatrixEntry current = last;
while (current.getPredecessor() != null) {
//check which operation was used by comparing indices.
final FullMatrixEntry pred = current.getPredecessor();
final Node left, right;
final OperationType type;
final double[] local;
if (current.getJ() == pred.getJ()) {
//in this case we have a deletion.
left = a.getNodes().get(current.getI() - 1);
right = null;
local = getSpecification().calculateDeletionCosts(left);
type = OperationType.DELETION;
} else if (current.getI() == pred.getI()) {
//in this case we have an insertion.
left = null;
right = b.getNodes().get(current.getJ() - 1);
local = getSpecification().calculateInsertionCosts(right);
type = OperationType.INSERTION;
} else {
//in this case we have a replacement.
left = a.getNodes().get(current.getI() - 1);
right = b.getNodes().get(current.getJ() - 1);
local = getSpecification().calculateReplacementCosts(left, right);
type = OperationType.REPLACEMENT;
}
final Operation op = new Operation(left, right, type, path);
op.setComparatorDistances(local);
ops.push(op);
current = pred;
}
while (!ops.empty()) {
path.getOperations().add(ops.pop());
}
return path;
}
public static class FullMatrixEntry implements AlignmentMatrixEntry {
private final double score;
private final int i;
private final int j;
private final FullMatrixEntry predecessor;
public FullMatrixEntry(double score, int i, int j, FullMatrixEntry predecessor) {
this.score = score;
this.i = i;
this.j = j;
this.predecessor = predecessor;
}
public int getI() {
return i;
}
public int getJ() {
return j;
}
public FullMatrixEntry getPredecessor() {
return predecessor;
}
public double getScore() {
return score;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy