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

de.citec.tcs.alignment.AlignmentMap Maven / Gradle / Ivy

/* 
 * TCS Alignment Toolbox Version 3
 * 
 * Copyright (C) 2016
 * Benjamin Paaßen
 * 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.DerivableComparator;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

/**
 * This is a Map-based datastructure implementing a mapping from scores to Alignments. It is
 * also able to calculate the derivative of all given Alignments weighted by their score.
 *
 * The weighting that is used can be chosen by the user.
 *
 * @author Benjamin Paassen - [email protected]
 * @param  the class of the elements in the left input sequence.
 * @param  the class of the elements in the right input sequence.
 */
public class AlignmentMap implements DerivableAlignmentDistance {

	@NonNull
	private final TreeMap>> actualMap = new TreeMap<>();
	private int size = 0;
	/**
	 * The weighting that is used during derivative calculation.
	 *
	 * @param weighting the weighting that is used during derivative
	 * calculation.
	 *
	 * @return the weighting that is used during derivative calculation.
	 */
	@Getter
	@Setter
	@NonNull
	private DissimilarityWeighting weighting = DissimilarityWeighting.SOFTMIN;

	public AlignmentMap() {
		super();
	}

	/**
	 * Adds a new Alignment to this map.
	 *
	 * @param path a new Alignment.
	 */
	public void put(@NonNull final Alignment path) {
		size++;
		ArrayList> list = actualMap.get(path.getDistance());
		if (list == null) {
			list = new ArrayList<>();
			actualMap.put(path.getDistance(), list);
		}
		list.add(path);
	}

	/**
	 * Returns the number of Alignments stored in this map.
	 *
	 * @return the number of Alignments stored in this map.
	 */
	public int getSize() {
		return size;
	}

	/**
	 * Returns all Alignments stored in this map in order of their score (from good/low to
	 * bad/high).
	 *
	 * @return all Alignments stored in this map in order of their score (from good/low to
	 * bad/high).
	 */
	public List> getAllAlignments() {
		final ArrayList> list = new ArrayList<>();
		for (final ArrayList> paths : actualMap.values()) {
			list.addAll(paths);
		}
		return list;
	}

	/**
	 * Returns all Alignments for the given score. If the score is not found within this map, an
	 * empty list is returned.
	 *
	 * @param score a score.
	 *
	 * @return all paths with the given score.
	 */
	public List> getAlignments(double score) {
		final ArrayList> list = actualMap.get(score);
		if (list == null) {
			return new ArrayList<>();
		}
		return list;
	}

	/**
	 * Get all scores (sorted from low to high) for which Alignments exist within this map.
	 *
	 * @return all scores for which Alignments exist within this map.
	 */
	public List getScores() {
		final ArrayList returnList = new ArrayList<>(actualMap.keySet());
		return returnList;
	}

	/**
	 * Removes all Alignments with the given score from the map and returns them. If the score is
	 * not found within this map an empty list is returned.
	 *
	 * @param score a score.
	 *
	 * @return all Alignments with the given score.
	 */
	public List> removeAlignments(double score) {
		final ArrayList> list = actualMap.remove(score);
		if (list == null) {
			return new ArrayList<>();
		}
		size -= list.size();
		return list;
	}

	/**
	 * Returns the lowest/best score stored in this map.
	 *
	 * @return the lowest/best score stored in this map.
	 */
	public double lowestScore() {
		return actualMap.firstKey();
	}

	/**
	 * Returns the highest/worst score stored in this map.
	 *
	 * @return the highest/worst score stored in this map.
	 */
	public double highestScore() {
		return actualMap.lastKey();
	}

	/**
	 * Returns the average score according to the given weighting scheme.
	 *
	 * @return the average score according to the given weighting scheme.
	 */
	public double averageScore() {
		if (actualMap.isEmpty()) {
			throw new UnsupportedOperationException("This AlignmentMap is empty.");
		}

		//first calculate the weights for all paths.
		final List> allPaths = getAllAlignments();
		final double[] scores = new double[allPaths.size()];
		int l = 0;
		for (Alignment path : allPaths) {
			scores[l] = path.getDistance();
			l++;
		}
		final double[] weights = weighting.calculateWeighting(scores);
		double avgScore = 0;
		for (l = 0; l < allPaths.size(); l++) {
			avgScore += scores[l] * weights[l];
		}
		return avgScore;
	}

	@Override
	public double[] computeGradient(@NonNull final DerivableComparator comp) {

		final int P = comp.getNumberOfParameters();
		final double[] gradient = new double[P];

		if (getSize() == 0) {
			return gradient;
		}
		//first calculate the weights for all paths.
		final List> allPaths = getAllAlignments();
		final double[] scores = new double[allPaths.size()];
		int l = 0;
		for (Alignment path : allPaths) {
			scores[l] = path.getDistance();
			l++;
		}
		final double[] weights = weighting.calculateWeighting(scores);
		/*
		 * now we let each path calculate its derivative and weight it according
		 * to the weighting specified.
		 */
		l = 0;
		for (final Alignment path : allPaths) {
			final double[] pathGradient = path.computeGradient(comp);
			for (int p = 0; p < P; p++) {
				gradient[p] += weights[l] * pathGradient[p];
			}
			l++;
		}
		return gradient;
	}

	/**
	 * This transforms the AlignmentMap to a matrix, mostly for visualization purposes. The matrix
	 * is equivalent the dynamic programming algorithm of the StrictAlgorithm that created this
	 * AlignmentMap. However, only those entries are non-zero that are relevant for at least one
	 * Alignment in this map.
	 * The value of the output matrix is defined as the weighted average over all Alignment toMatrix
	 * outputs.
	 *
	 * @return the dynamic programming matrix of the algorithm that created this AlignmentMap with
	 * non-zero entries at positions that are relevant for at least one Alignment.
	 */
	public double[][] toMatrix() {
		//first calculate the weights for all Alignments.
		final List> alignments = getAllAlignments();
		final double[] scores = new double[alignments.size()];
		int l = 0;
		for (final Alignment alignment : alignments) {
			scores[l] = alignment.getDistance();
			l++;
		}
		final double[] weights = weighting.calculateWeighting(scores);

		final int m = getLeft().size();
		final int n = getRight().size();

		final double[][] out = new double[m + 1][n + 1];
		l = 0;
		for (final Alignment alignment : alignments) {
			int i = 0;
			int j = 0;
			double oldScore = 0;
			for (final Operation op : alignment) {
				switch (op.getType()) {
					case DELETION:
					case SKIPDELETION:
					case DELETIONREPLACEMENT:
						i++;
						break;
					case INSERTION:
					case SKIPINSERTION:
					case INSERTIONREPLACEMENT:
						j++;
						break;
					case REPLACEMENT:
						i++;
						j++;
						break;
					default:
						throw new UnsupportedOperationException("Unsupported operation: " + op.getType());
				}
				out[i][j] += weights[l] * (oldScore + op.getDistance());
				oldScore = out[i][j];
			}
			l++;
		}
		return out;
	}

	/**
	 * Returns the average distance of all stored Alignments.
	 *
	 * @return the average distance of all stored Alignments.
	 */
	@Override
	public double getDistance() {
		return averageScore();
	}

	@Override
	public List getLeft() {
		if (actualMap.isEmpty()) {
			throw new UnsupportedOperationException("This AlignmentMap is empty.");
		}
		List left = null;
		for (final Alignment alignment : getAllAlignments()) {
			if (left == null) {
				left = alignment.getLeft();
			} else {
				if (left != alignment.getLeft()) {
					throw new UnsupportedOperationException("The Alignments in this list have no consistent left sequence.");
				}
			}
		}
		return left;
	}

	@Override
	public List getRight() {
		if (actualMap.isEmpty()) {
			throw new UnsupportedOperationException("This AlignmentMap is empty.");
		}
		List right = null;
		for (final Alignment alignment : getAllAlignments()) {
			if (right == null) {
				right = alignment.getRight();
			} else {
				if (right != alignment.getRight()) {
					throw new UnsupportedOperationException("The Alignments in this list have no consistent right sequence.");
				}
			}
		}
		return right;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy