///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2007 University of Texas at Austin and (C) 2005
// University of Pennsylvania and Copyright (C) 2002, 2003 University
// of Massachusetts Amherst, Department of Computer Science.
//
// This software is licensed under the terms of the Common Public
// License, Version 1.0 or (at your option) any subsequent version.
//
// The license is approved by the Open Source Initiative, and is
// available from their website at http://www.opensource.org.
///////////////////////////////////////////////////////////////////////////////
package mstparser;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntDoubleHashMap;
import gnu.trove.TLinkedList;
import java.util.ListIterator;
/**
* A <tt>FeatureVector</tt> that can hold up to two <tt>FeatureVector</tt>
* instances inside it, which allows for a very quick concatenation operation.
*
* <p>Also, in order to avoid copies, the second of these internal
* <tt>FeatureVector</tt> instances can be negated, so that it has the effect of
* subtracting any values rather than adding them.
*
* <p> Created: Sat Nov 10 15:25:10 2001 </p>
*
* @author Jason Baldridge
* @version $Id: FeatureVector.java 90 2007-01-17 07:42:20Z jasonbaldridge $
* @see mstparser.Feature
*/
public final class FeatureVector extends TLinkedList {
private FeatureVector subfv1 = null;
private FeatureVector subfv2 = null;
private boolean negateSecondSubFV = false;
public FeatureVector() {
}
public FeatureVector(FeatureVector fv1) {
subfv1 = fv1;
}
public FeatureVector(FeatureVector fv1, FeatureVector fv2) {
subfv1 = fv1;
subfv2 = fv2;
}
public FeatureVector(FeatureVector fv1, FeatureVector fv2, boolean negSecond) {
subfv1 = fv1;
subfv2 = fv2;
negateSecondSubFV = negSecond;
}
public FeatureVector(int[] keys) {
for (int i = 0; i < keys.length; i++) {
add(new Feature(keys[i], 1.0));
}
}
public void add(int index, double value) {
add(new Feature(index, value));
}
public int[] keys() {
TIntArrayList keys = new TIntArrayList();
addKeysToList(keys);
return keys.toNativeArray();
}
private void addKeysToList(TIntArrayList keys) {
if (null != subfv1) {
subfv1.addKeysToList(keys);
if (null != subfv2) {
subfv2.addKeysToList(keys);
}
}
ListIterator it = listIterator();
while (it.hasNext()) {
keys.add(((Feature) it.next()).index);
}
}
public final FeatureVector cat(FeatureVector fl2) {
return new FeatureVector(this, fl2);
}
// fv1 - fv2
public FeatureVector getDistVector(FeatureVector fl2) {
return new FeatureVector(this, fl2, true);
}
public final double getScore(double[] parameters) {
return getScore(parameters, false);
}
private double getScore(double[] parameters, boolean negate) {
double score = 0.0;
if (null != subfv1) {
score += subfv1.getScore(parameters, negate);
if (null != subfv2) {
if (negate) {
score += subfv2.getScore(parameters, !negateSecondSubFV);
} else {
score += subfv2.getScore(parameters, negateSecondSubFV);
}
}
}
ListIterator it = listIterator();
if (negate) {
while (it.hasNext()) {
Feature f = (Feature) it.next();
score -= parameters[f.index] * f.value;
}
} else {
while (it.hasNext()) {
Feature f = (Feature) it.next();
score += parameters[f.index] * f.value;
}
}
return score;
}
public void update(double[] parameters, double[] total, double alpha_k, double upd) {
update(parameters, total, alpha_k, upd, false);
}
private void update(double[] parameters, double[] total,
double alpha_k, double upd, boolean negate) {
if (null != subfv1) {
subfv1.update(parameters, total, alpha_k, upd, negate);
if (null != subfv2) {
if (negate) {
subfv2.update(parameters, total, alpha_k, upd, !negateSecondSubFV);
} else {
subfv2.update(parameters, total, alpha_k, upd, negateSecondSubFV);
}
}
}
ListIterator it = listIterator();
if (negate) {
while (it.hasNext()) {
Feature f = (Feature) it.next();
parameters[f.index] -= alpha_k * f.value;
total[f.index] -= upd * alpha_k * f.value;
}
} else {
while (it.hasNext()) {
Feature f = (Feature) it.next();
parameters[f.index] += alpha_k * f.value;
total[f.index] += upd * alpha_k * f.value;
}
}
}
public double dotProduct(FeatureVector fl2) {
TIntDoubleHashMap hm1 = new TIntDoubleHashMap(this.size());
addFeaturesToMap(hm1, false);
hm1.compact();
TIntDoubleHashMap hm2 = new TIntDoubleHashMap(fl2.size());
fl2.addFeaturesToMap(hm2, false);
hm2.compact();
int[] keys = hm1.keys();
double result = 0.0;
for (int i = 0; i < keys.length; i++) {
result += hm1.get(keys[i]) * hm2.get(keys[i]);
}
return result;
}
private void addFeaturesToMap(TIntDoubleHashMap map, boolean negate) {
if (null != subfv1) {
subfv1.addFeaturesToMap(map, negate);
if (null != subfv2) {
if (negate) {
subfv2.addFeaturesToMap(map, !negateSecondSubFV);
} else {
subfv2.addFeaturesToMap(map, negateSecondSubFV);
}
}
}
ListIterator it = listIterator();
if (negate) {
while (it.hasNext()) {
Feature f = (Feature) it.next();
if (!map.adjustValue(f.index, -f.value)) {
map.put(f.index, -f.value);
}
}
} else {
while (it.hasNext()) {
Feature f = (Feature) it.next();
if (!map.adjustValue(f.index, f.value)) {
map.put(f.index, f.value);
}
}
}
}
@Override
public final String toString() {
StringBuilder sb = new StringBuilder();
toString(sb);
return sb.toString();
}
private void toString(StringBuilder sb) {
if (null != subfv1) {
subfv1.toString(sb);
if (null != subfv2) {
subfv2.toString(sb);
}
}
ListIterator it = listIterator();
while (it.hasNext()) {
sb.append(it.next().toString()).append(' ');
}
}
}