de.citec.tcs.alignment.AlignmentPath 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.DerivableComparator;
import de.citec.tcs.alignment.comparators.SparseDerivableComparator;
import de.citec.tcs.alignment.comparators.SparseLocalDerivative.SparseDeriativeEntry;
import de.citec.tcs.alignment.sequence.Sequence;
import de.citec.tcs.alignment.sequence.Value;
import java.util.ArrayList;
import java.util.Iterator;
/**
* This class models an alignment path as it is given out by a strict alignment.
* Such a path is defined as a sequence of alignment operations transforming the
* left input Sequence to the right one.
*
* By listing those operations AlignmentPaths are able to calculate the strict
* derivative of the AlignmentAlgorithm.
*
* @author Benjamin Paassen - [email protected]
*/
public class AlignmentPath implements AlignmentDerivativeAlgorithm {
private final ArrayList operations = new ArrayList();
private final AlignmentSpecification specificaton;
private final Sequence left;
private final Sequence right;
private final double distance;
public AlignmentPath(AlignmentSpecification specificaton, Sequence left, Sequence right,
double distance) {
this.specificaton = specificaton;
this.left = left;
this.right = right;
if (left.getNodeSpecification() != specificaton.getNodeSpecification()
&& !left.getNodeSpecification().equals(specificaton.getNodeSpecification())) {
throw new IllegalArgumentException(
"The first input sequence has an unexpected node specification!");
}
if (left.getNodeSpecification() != right.getNodeSpecification()
&& !left.getNodeSpecification().equals(right.getNodeSpecification())) {
throw new IllegalArgumentException(
"The node specifications of both input sequences to not match!");
}
this.distance = distance;
}
/**
*
* @return The specification that was the basis for this alignment.
*/
public AlignmentSpecification getSpecificaton() {
return specificaton;
}
/**
*
* @return The operations that were used in this AlignmentPath.
*/
public ArrayList getOperations() {
return operations;
}
/**
* {@inheritDoc }
*/
@Override
public Sequence getLeft() {
return left;
}
/**
* {@inheritDoc }
*/
@Override
public Sequence getRight() {
return right;
}
/**
* {@inheritDoc }
*/
@Override
public double getDistance() {
return distance;
}
/**
* This transforms the AlignmentPath to a matrix, mostly for visualization
* purposes. The matrix is equivalent the dynamic programming algorithm of
* the StrictAlgorithm that created this path. However, only those entries
* are non-zero that are relevant for this path.
*
* @return the dynamic programming matrix of the algorithm that created this
* path with non-zero entries at positions that are relevant for this path.
*/
public double[][] toMatrix() {
final double[][] out = new double[left.getNodes().size() + 1][right.getNodes().size() + 1];
int i = 0;
int j = 0;
double oldScore = 0;
for (final Operation op : operations) {
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] = oldScore + op.getWeightedLocalCost();
oldScore = out[i][j];
}
return out;
}
/**
* {@inheritDoc }
*/
@Override
protected Object clone() throws CloneNotSupportedException {
final AlignmentPath clone = new AlignmentPath(specificaton, left, right,
distance);
for (final Operation op : operations) {
final Operation opClone = new Operation(op.getLeft(), op.getRight(),
op.getType(), clone);
opClone.setComparatorDistances(op.getComparatorDistances());
clone.operations.add(opClone);
}
return clone;
}
/**
* {@inheritDoc }
*/
@Override
public double[] calculateWeightDerivative() {
final double[] derivative = new double[specificaton.getWeighting().length];
for (final Operation op : operations) {
final double[] comparatorDistances = op.getComparatorDistances();
for (int k = 0; k < derivative.length; k++) {
derivative[k] += comparatorDistances[k];
}
}
return derivative;
}
/**
* {@inheritDoc }
*/
@Override
public Y calculateParameterDerivative(
DerivableComparator comp, String keyword) {
return comp.transformToResult(calculateRawParameterDerivative(comp, keyword));
}
/**
* {@inheritDoc }
*/
@Override
public double[] calculateRawParameterDerivative(
DerivableComparator comp, String keyword) {
boolean sparse = comp instanceof SparseDerivableComparator;
final SparseDerivableComparator sparseComp;
if (sparse) {
sparseComp = (SparseDerivableComparator) comp;
} else {
sparseComp = null;
}
final int P = comp.getNumberOfParameters();
final double[] derivatives = new double[P];
final int k = specificaton.getKeywordIndex(keyword);
if (specificaton.getComparator(k) != comp) {
throw new IllegalArgumentException(
"The given comparator was not used for the given keyword!");
}
final double weight = specificaton.getWeighting()[k];
if (weight == 0) {
/*
* if the comparator has no weight, we return an empty array without
* doing any calculation.
*/
return derivatives;
}
final int origK = specificaton.getOriginalIndex(k);
for (final Operation op : operations) {
final X left, right;
if (op.getLeft() == null) {
left = null;
} else {
left = (X) op.getLeft().getValue(origK);
}
if (op.getRight() == null) {
right = null;
} else {
right = (X) op.getRight().getValue(origK);
}
//if we do not have a sparse comparator, we iterate over all parameters.
if (!sparse) {
for (int p = 0; p < P; p++) {
derivatives[p] += weight * comp.calculateLocalDerivative(p,
left, right, op.getType());
}
} else {
final Iterator it = sparseComp.
calculateSparseLocalDerivative(left, right,
op.getType()).iterator();
while (it.hasNext()) {
final SparseDeriativeEntry sparseLocalDerivative = it.next();
derivatives[sparseLocalDerivative.getParameterIndex()]
+= weight * sparseLocalDerivative.getDerivative();
}
}
}
return derivatives;
}
/**
* {@inheritDoc }
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Overall Score = ");
builder.append(distance);
final int K = specificaton.size();
if (K > 1) {
builder.append("\nWeighting:\n");
for (int k = 0; k < K; k++) {
builder.append(specificaton.getKeyword(k));
builder.append(" : ");
builder.append(specificaton.getWeighting()[k]);
builder.append("\n");
}
}
builder.append("\n");
for (final Operation op : operations) {
builder.append(op.toString());
builder.append("\n");
if (K > 1) {
builder.append("\n");
}
}
int sub = 1;
if (K > 1) {
sub++;
}
builder.delete(builder.length() - sub, builder.length());
return builder.toString();
}
/**
* {@inheritDoc }
*/
@Override
public int hashCode() {
int hash = 3;
hash = 23 * hash + (this.operations != null ? this.operations.hashCode() : 0);
hash = 23 * hash + (this.specificaton != null ? this.specificaton.hashCode() : 0);
return hash;
}
/**
* {@inheritDoc }
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final AlignmentPath other = (AlignmentPath) obj;
if (this.operations != other.operations
&& (this.operations == null || !this.operations.equals(other.operations))) {
return false;
}
if (this.specificaton != other.specificaton
&& (this.specificaton == null || !this.specificaton.equals(other.specificaton))) {
return false;
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy