de.citec.tcs.alignment.Operation 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.GapComparator;
import de.citec.tcs.alignment.comparators.OperationType;
import de.citec.tcs.alignment.comparators.SkipComparator;
import de.citec.tcs.alignment.sequence.Node;
import java.util.Arrays;
/**
* This defines an applied alignment operation. It is specified by the nodes
* that have been aligned from the left or the right sequence in the alignment.
* If a node was replaced by a gap it is denoted here as a null reference.
*
* @author Benjamin Paassen - [email protected]
*/
public class Operation {
private final Node left;
private final Node right;
private final OperationType type;
private final AlignmentPath path;
private final double[] comparatorDistances;
/**
* This constructs an Operation within an AlignmentPath.
*
* @param left The Node from the left input sequence that was used here or
* null if this is a DELETION/SKIPDELETION operation.
* @param right The Node from the right input sequence that was used here or
* null if this is an INSERTION/SKIPINSERTION operation.
* @param type The type of this Operation. Please refer to the OperationType
* class for more information.
* @param path The AlignmentPath this Operation belongs to.
*/
public Operation(Node left, Node right, OperationType type, AlignmentPath path) {
this.left = left;
this.right = right;
this.type = type;
this.path = path;
this.comparatorDistances = new double[path.getSpecificaton().size()];
//check validity.
switch (type) {
case DELETION:
case SKIPDELETION:
if (right != null) {
throw new RuntimeException("Expected null for a gap/skip but was not null!");
}
break;
case INSERTION:
case SKIPINSERTION:
if (left != null) {
throw new RuntimeException("Expected null for a gap/skip but was not null!");
}
break;
}
switch (type) {
case DELETION:
case SKIPDELETION:
case DELETIONREPLACEMENT:
case INSERTIONREPLACEMENT:
case REPLACEMENT:
if (left.getSequence() != path.getLeft()) {
throw new RuntimeException(
"The given left node does not belong to the left sequence of this path!");
}
}
switch (type) {
case INSERTION:
case SKIPINSERTION:
case INSERTIONREPLACEMENT:
case DELETIONREPLACEMENT:
case REPLACEMENT:
if (right.getSequence() != path.getRight()) {
throw new RuntimeException(
"The given right node does not belong to the right sequence of this path!");
}
}
}
/**
*
* @return The Node from the left input sequence that was used here or null
* if this is a DELETION/SKIPDELETION operation.
*/
public Node getLeft() {
return left;
}
/**
*
* @return The Node from the right input sequence that was used here or null
* if this is an INSERTION/SKIPINSERTION operation.
*/
public Node getRight() {
return right;
}
/**
*
* @return The AlignmentPath this Operation belongs to.
*/
public AlignmentPath getPath() {
return path;
}
/**
*
* @return The type of this Operation. Please refer to the OperationType
* class for more information.
*/
public OperationType getType() {
return type;
}
/**
* Returns the local costs given by the Comparators specified for this
* Alignment to align the left Node in this Operation with the right Node
* (or deleting, inserting, skipping nodes respectively).
*
* Please refer to the corresponding setter method for more information.
*
* @return The local costs given by the Comparators specified for this
* Alignment to align the left Node in this Operation with the right Node
* (or deleting, inserting, skipping nodes respectively).
*/
public double[] getComparatorDistances() {
return comparatorDistances;
}
/**
*
* @return The vector product of the keyword weighting specified in the
* AlignmentSpecification and the ComparatorDistances.
*/
public double getWeightedLocalCost() {
double sum = 0;
final double[] weighting = path.getSpecificaton().getWeighting();
for (int i = 0; i < comparatorDistances.length; i++) {
if (weighting[i] > 0) {
sum += weighting[i] * comparatorDistances[i];
}
}
return sum;
}
/**
* Sets the local costs given by the Comparators specified for this
* Alignment to align the left Node in this Operation with the right Node
* (or deleting, inserting, skipping nodes respectively).
*
* Say the comparators are functions
*
* c_k : V_k x V_k to Real Numbers
*
* where V_k is the space of possible Values for the keyword k. Say that a_k
* and b_k are the values for the keyword k in the left node (a) and the
* right node (b).
*
* Than the return value here is the vector c_k(a_k,b_k) for all k.
*
* @param distances The local costs given by the Comparators specified for
* this Alignment to align the left Node in this Operation with the right
* Node (or deleting, inserting, skipping nodes respectively).
*/
public void setComparatorDistances(double[] distances) {
if (comparatorDistances.length != distances.length) {
throw new RuntimeException("The wrong number of distances was given!");
}
System.arraycopy(distances, 0, comparatorDistances, 0, distances.length);
}
public static double[] calculateComparatorDistances(OperationType op,
Node left, Node right, AlignmentSpecification spec) {
double[] costs = new double[spec.size()];
for (int k = 0; k < costs.length; k++) {
switch (op) {
case REPLACEMENT:
case DELETIONREPLACEMENT:
case INSERTIONREPLACEMENT:
costs[k] = spec.getComparator(k).compare(
left.getValue(spec.getOriginalIndex(k)),
right.getValue(spec.getOriginalIndex(k)));
break;
case DELETION: {
final GapComparator comp = (GapComparator) spec.getComparator(k);
costs[k] = comp.delete(left.getValue(spec.getOriginalIndex(k)));
break;
}
case INSERTION: {
final GapComparator comp = (GapComparator) spec.getComparator(k);
costs[k] = comp.insert(right.getValue(spec.getOriginalIndex(k)));
break;
}
case SKIPDELETION: {
final SkipComparator comp = (SkipComparator) spec.getComparator(k);
costs[k] = comp.skipDelete(left.getValue(spec.getOriginalIndex(k)));
break;
}
case SKIPINSERTION: {
final SkipComparator comp = (SkipComparator) spec.getComparator(k);
costs[k] = comp.skipInsert(right.getValue(spec.getOriginalIndex(k)));
break;
}
default:
throw new UnsupportedOperationException("Unknown operation: " + op);
}
}
return costs;
}
/**
* {@inheritDoc }
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
final int K = path.getSpecificaton().size();
if (K > 1) {
builder.append(type);
builder.append("\nWeighted Local Cost = ");
builder.append(getWeightedLocalCost());
builder.append("\n");
}
for (int k = 0; k < K; k++) {
if (K > 1) {
builder.append(path.getSpecificaton().getKeyword(k));
builder.append(" : ");
}
if (left != null) {
builder.append(left.getValue(path.getSpecificaton().getOriginalIndex(k)));
} else {
switch (type) {
case INSERTION:
builder.append("-");
break;
case SKIPINSERTION:
builder.append("_");
break;
}
}
builder.append(" vs. ");
if (right != null) {
builder.append(right.getValue(path.getSpecificaton().getOriginalIndex(k)));
} else {
switch (type) {
case DELETION:
builder.append("-");
break;
case SKIPDELETION:
builder.append("_");
break;
}
}
builder.append(" = ");
builder.append(comparatorDistances[k]);
if (K > 1) {
builder.append("\n");
}
}
if (K > 1) {
builder.delete(builder.length() - 1, builder.length());
}
return builder.toString();
}
/**
* {@inheritDoc }
*/
@Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + (this.left != null ? this.left.hashCode() : 0);
hash = 53 * hash + (this.right != null ? this.right.hashCode() : 0);
hash = 53 * hash + (this.type != null ? this.type.hashCode() : 0);
hash = 53 * hash + Arrays.hashCode(this.comparatorDistances);
return hash;
}
/**
* {@inheritDoc }
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Operation other = (Operation) obj;
if (this.left != other.left && (this.left == null || !this.left.equals(other.left))) {
return false;
}
if (this.right != other.right && (this.right == null || !this.right.equals(other.right))) {
return false;
}
if (this.type != other.type) {
return false;
}
if (!Arrays.equals(this.comparatorDistances, other.comparatorDistances)) {
return false;
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy