
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