001/** 
002 * Copyright (c) 2007-2008, Regents of the University of Colorado 
003 * All rights reserved.
004 * 
005 * Redistribution and use in source and binary forms, with or without
006 * modification, are permitted provided that the following conditions are met:
007 * 
008 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
009 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
010 * Neither the name of the University of Colorado at Boulder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
011 * 
012 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
013 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
014 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
015 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
016 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
017 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
018 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
019 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
020 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
021 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
022 * POSSIBILITY OF SUCH DAMAGE. 
023 */
024package org.cleartk.ml.util.featurevector;
025
026import java.util.Iterator;
027import java.util.NoSuchElementException;
028
029/**
030 * <br>
031 * Copyright (c) 2007-2008, Regents of the University of Colorado <br>
032 * All rights reserved.
033 * 
034 * 
035 * @author Philipp Wetzler
036 * 
037 */
038public abstract class FeatureVector implements Iterable<FeatureVector.Entry> {
039
040  public void add(FeatureVector other) throws InvalidFeatureVectorValueException {
041    for (FeatureVector.Entry entry : other) {
042      this.set(entry.index, this.get(entry.index) + entry.value);
043    }
044  }
045
046  public void multiply(double factor) throws InvalidFeatureVectorValueException {
047    for (FeatureVector.Entry entry : this) {
048      this.set(entry.index, this.get(entry.index) * factor);
049    }
050  }
051
052  public double l2Norm() {
053    double l = 0.0;
054
055    for (FeatureVector.Entry entry : this) {
056      l += entry.value * entry.value;
057    }
058
059    return Math.sqrt(l);
060  }
061
062  @Override
063  public boolean equals(Object o) {
064    FeatureVector other;
065    try {
066      other = (FeatureVector) o;
067    } catch (ClassCastException e) {
068      return false;
069    }
070
071    Iterator<Entry> thisIt = this.iterator();
072    Iterator<Entry> otherIt = other.iterator();
073    while (thisIt.hasNext() || otherIt.hasNext()) {
074      Entry thisEntry;
075      Entry otherEntry;
076      try {
077        thisEntry = thisIt.next();
078        otherEntry = otherIt.next();
079      } catch (NoSuchElementException e) {
080        return false;
081      }
082
083      if (!thisEntry.equals(otherEntry))
084        return false;
085    }
086
087    return true;
088  }
089
090  @Override
091  public int hashCode() {
092    int result = 1451;
093    for (Entry e : this) {
094      result = 757 * result + e.hashCode();
095    }
096    return result;
097  }
098
099  /**
100   * Set the feature at index to value.
101   */
102  public abstract void set(int index, double value) throws InvalidFeatureVectorValueException;
103
104  /**
105   * Return the value at index.
106   * 
107   * @param index
108   *          The index
109   * @return The value at the index
110   */
111  public abstract double get(int index);
112
113  /**
114   * Gives an iterator over the non-zero features.
115   */
116  public abstract Iterator<Entry> iterator();
117
118  public double innerProduct(FeatureVector other) {
119    double result = 0.0;
120
121    for (FeatureVector.Entry entry : other) {
122      result += this.get(entry.index) * entry.value;
123    }
124
125    return result;
126  }
127
128  public static class Entry {
129    public Entry(int index, double value) {
130      this.index = index;
131      this.value = value;
132    }
133
134    @Override
135    public boolean equals(Object o) {
136      Entry other;
137      try {
138        other = (Entry) o;
139      } catch (ClassCastException e) {
140        return false;
141      }
142
143      if (this.index != other.index)
144        return false;
145
146      if (this.value != other.value)
147        return false;
148
149      return true;
150    }
151
152    @Override
153    public int hashCode() {
154      int result = 83;
155      result = 47 * result + this.index;
156      result = 47 * result + new Double(this.value).hashCode();
157      return result;
158    }
159
160    public final int index;
161
162    public final double value;
163  }
164
165}