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

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