
de.citec.tcs.alignment.AlignmentMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of algorithms Show documentation
Show all versions of algorithms Show documentation
This module defines the interface for AlignmentAlgorithms as well as some helper classes. An
AlignmentAlgorithm computes an Alignment of two given input sequences, given a Comparator that
works in these sequences.
More details on the AlignmentAlgorithm can be found in the respective interface. More information
on Comparators can be found in the comparators module.
The resulting 'Alignment' may be just a real-valued dissimilarity between the input sequence or
may incorporate additional information, such as a full Alignment, a PathList, a PathMap or a
CooptimalModel. If those results support the calculation of a Gradient, they implement the
DerivableAlignmentDistance interface.
In more detail, the Alignment class represents the result of a backtracing scheme, listing all
Operations that have been applied in one co-optimal Alignment.
A classic AlignmentAlgorithm does not result in a differentiable dissimilarity, because the
minimum function is not differentiable. Therefore, this package also contains utility functions
for a soft approximation of the minimum function, namely Softmin.
For faster (parallel) computation of many different alignments or gradients we also provide the
ParallelProcessingEngine, the SquareParallelProcessingEngine and the ParallelGradientEngine.
The newest version!
/*
* 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