All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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