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

de.citec.tcs.alignment.PathMap 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.sequence.Sequence;
import de.citec.tcs.alignment.sequence.Value;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

/**
 * This is a TreeMap-based datastructure implementing a mapping from scores to
 * AlignmentPaths. It is also able to calculate the derivative of all given
 * paths weighted by their score.
 *
 * The weighting that is used can be chosen by the user.
 *
 * @author Benjamin Paassen - [email protected]
 */
public class PathMap implements AlignmentDerivativeAlgorithm {

	private final TreeMap> actualMap
			= new TreeMap>();
	private int size = 0;
	private ScoreBasedWeighting weighting = ScoreBasedWeighting.SOFTMIN;

	public PathMap() {
		super();
	}

	/**
	 * Returns the weighting that is used during derivative calculation.
	 *
	 * @return the weighting that is used during derivative calculation.
	 */
	public ScoreBasedWeighting getWeighting() {
		return weighting;
	}

	/**
	 * Sets the weighting that is used during derivative calculation.
	 *
	 * @param weighting the weighting that is used during derivative
	 *                  calculation.
	 */
	public void setWeighting(ScoreBasedWeighting weighting) {
		this.weighting = weighting;
	}

	/**
	 * Adds a new AlignmentPath to this map.
	 *
	 * @param path a new AlignmentPath.
	 */
	public void put(AlignmentPath 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 paths stored in this map.
	 *
	 * @return the number of paths stored in this map.
	 */
	public int getSize() {
		return size;
	}

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

	/**
	 * Returns all paths with 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 getPaths(double score) {
		final ArrayList list = actualMap.get(score);
		if (list == null) {
			return new ArrayList();
		}
		return list;
	}

	/**
	 * Get all scores for which paths exist within this map.
	 *
	 * @return all scores for which paths exist within this map.
	 */
	public List getScores() {
		final ArrayList returnList = new ArrayList(actualMap.keySet());
		return returnList;
	}

	/**
	 * Removes all AlignmentPaths 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 AlignmentPaths with the given score from the map and returns
	 *         them.
	 */
	public List removeValues(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 PathMap is empty.");
		}

		//first calculate the weights for all paths.
		final List allPaths = getAllPaths();
		final double[] scores = new double[allPaths.size()];
		int l = 0;
		for (AlignmentPath 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;
	}

	/**
	 * {@inheritDoc }
	 */
	@Override
	public  Y calculateParameterDerivative(
			DerivableComparator comp, String keyword) {
		return comp.transformToResult(calculateRawParameterDerivative(comp, keyword));
	}

	/**
	 * {@inheritDoc }
	 */
	@Override
	public  double[] calculateRawParameterDerivative(
			DerivableComparator comp, String keyword) {

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

		if (getSize() == 0) {
			return derivatives;
		}
		//first calculate the weights for all paths.
		final List allPaths = getAllPaths();
		final double[] scores = new double[allPaths.size()];
		int l = 0;
		for (AlignmentPath 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 AlignmentPath path : allPaths) {
			final double[] pathDerivatives = path.calculateRawParameterDerivative(
					comp, keyword);
			for (int p = 0; p < P; p++) {
				derivatives[p] += weights[l] * pathDerivatives[p];
			}
			l++;
		}
		return derivatives;
	}

	/**
	 * {@inheritDoc }
	 */
	public double[] calculateWeightDerivative() {
		if (getSize() == 0) {
			throw new UnsupportedOperationException(
					"Weight derivative without any paths is not defined.");
		}

		//first calculate the weights for all paths.
		final List allPaths = getAllPaths();
		final double[] scores = new double[allPaths.size()];
		int l = 0;
		for (AlignmentPath path : allPaths) {
			scores[l] = path.getDistance();
			l++;
		}
		final double[] weights = weighting.calculateWeighting(scores);

		/*
		 * now we let each path calculate its weight derivative and take the
		 * weighted minimum as discussed.
		 */
		final int K = actualMap.firstEntry().getValue().get(0).
				getSpecificaton().size();
		final double[] derivative = new double[K];
		l = 0;
		for (final AlignmentPath path : allPaths) {
			final double[] pathDerivative = path.calculateWeightDerivative();
			for (int k = 0; k < K; k++) {
				derivative[k] += weights[l] * pathDerivative[k];
			}
			l++;
		}
		return derivative;
	}

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

		final int m = allPaths.get(0).getLeft().getNodes().size();
		final int n = allPaths.get(0).getRight().getNodes().size();

		final double[][] out = new double[m + 1][n + 1];
		l = 0;
		for (final AlignmentPath path : allPaths) {
			int i = 0;
			int j = 0;
			double oldScore = 0;
			for (final Operation op : path.getOperations()) {
				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.getWeightedLocalCost());
				oldScore = out[i][j];
			}
			l++;
		}
		return out;
	}

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

	/**
	 * {@inheritDoc }
	 */
	@Override
	public Sequence getLeft() {
		if (actualMap.isEmpty()) {
			throw new UnsupportedOperationException("This PathMap is empty.");
		}
		Sequence left = null;
		for (final AlignmentPath p : getAllPaths()) {
			if (left == null) {
				left = p.getLeft();
			} else {
				if (left != p.getLeft()) {
					throw new UnsupportedOperationException("The AlignmentPaths in this list have no consistent left sequence.");
				}
			}
		}
		return left;
	}

	/**
	 * {@inheritDoc }
	 */
	@Override
	public Sequence getRight() {
		if (actualMap.isEmpty()) {
			throw new UnsupportedOperationException("This PathMap is empty.");
		}
		Sequence right = null;
		for (final AlignmentPath p : getAllPaths()) {
			if (right == null) {
				right = p.getRight();
			} else {
				if (right != p.getRight()) {
					throw new UnsupportedOperationException("The AlignmentPaths in this list have no consistent right sequence.");
				}
			}
		}
		return right;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy