/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi 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.
Gephi 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 Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.clustering.plugin.mcl;
import java.util.HashMap;
import java.util.Iterator;
/**
* SparseVector represents a sparse vector.
* <p>
* Conventions: except for the inherited methods and normalise(double),
* operations leave <tt>this</tt> ummodified (immutable) if there is a return
* value. Within operations, no pruning of values close to zero is done. Pruning
* can be controlled via the prune() method.
*/
//Original author Gregor Heinrich
public class SparseVector extends HashMap<Integer, Double> {
private static final long serialVersionUID = 1L;
private int length = 0;
/**
* create empty vector
*/
public SparseVector() {
super();
}
/**
* create empty vector with length
*/
public SparseVector(int i) {
this();
length = i;
}
/**
* create vector from dense vector
*
* @param x
*/
public SparseVector(double[] x) {
this(x.length);
for (int i = 0; i < x.length; i++) {
if (x[i] != 0) {
put(i, x[i]);
}
}
}
/**
* copy constructor
*
* @param v
*/
public SparseVector(SparseVector v) {
super(v);
this.length = v.length;
}
/**
* get ensures it returns 0 for empty hash values or if index exceeds
* length.
*
* @param key
* @return val
*/
@Override
public Double get(Object key) {
Double b = super.get(key);
if (b == null) {
return 0.;
}
return b;
}
/**
* put increases the matrix size if the index exceeds the current size.
*
* @param key
* @param value
* @return
*/
@Override
public Double put(Integer key, Double value) {
length = Math.max(length, key + 1);
if (value == 0) {
return remove(key);
}
return super.put(key, value);
}
/**
* normalises the vector to 1.
*/
public void normalise() {
double invsum = 1. / sum();
for (int i : keySet()) {
mult(i, invsum);
}
}
/**
* normalises the vector to newsum
*
* @param the value to which the element sum
* @return the old element sum
*/
public double normalise(double newsum) {
double sum = sum();
double invsum = newsum / sum;
for (int i : keySet()) {
mult(i, invsum);
}
return sum;
}
/**
* sum of the elements
*
* @return
*/
private double sum() {
double sum = 0;
for (double a : values()) {
sum += a;
}
return sum;
}
/**
* power sum of the elements
*
* @return
*/
public double sum(double s) {
double sum = 0;
for (double a : values()) {
sum += Math.pow(a, s);
}
return sum;
}
/**
* mutable add
*
* @param v
*/
public void add(SparseVector v) {
for (int i : keySet()) {
add(i, v.get(i));
}
}
/**
* mutable mult
*
* @param i index
* @param a value
*/
public void mult(int i, double a) {
Double c = get(i);
c *= a;
put(i, c);
}
/**
* mutable factorisation
*
* @param a
*/
public void factor(double a) {
SparseVector s = copy();
for (int i : keySet()) {
s.mult(i, a);
}
}
/**
* immutable scalar product
*
* @param v
* @return scalar product
*/
public double times(SparseVector v) {
double sum = 0;
for (int i : keySet()) {
sum += get(i) * v.get(i);
}
return sum;
}
/**
* mutable Hadamard product (elementwise multiplication)
*
* @param v
*/
public void hadamardProduct(SparseVector v) {
for (int i : keySet()) {
put(i, v.get(i) * get(i));
}
}
/**
* mutable Hadamard power
*
* @param s
*/
public void hadamardPower(double s) {
for (int i : keySet().toArray(new Integer[0])) {
put(i, Math.pow(get(i), s));
}
}
/**
* mutable add
*
* @param i
* @param a
*/
public void add(int i, double a) {
length = Math.max(length, i + 1);
double c = get(i);
c += a;
put(i, c);
}
/**
* get the length of the vector
*
* @return
*/
public final int getLength() {
return length;
}
/**
* set the new length of the vector (regardless of the maximum index).
*
* @param length
*/
public final void setLength(int length) {
this.length = length;
}
/**
* copy the contents of the sparse vector
*
* @return
*/
public SparseVector copy() {
return new SparseVector(this);
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
for (int i : keySet()) {
sb.append(i).append("->").append(get(i)).append(", ");
}
return sb.toString();
}
/**
* get dense represenation
*
* @return
*/
public double[] getDense() {
double[] a = new double[length];
for (int i : keySet()) {
a[i] = get(i);
}
return a;
}
/**
* maximum element value
*
* @return
*/
public double max() {
double max = 0;
for (int i : keySet()) {
max = Math.max(get(i), max);
}
return max;
}
/**
* exponential sum, i.e., sum (elements^p)
*
* @param p
* @return
*/
public double expSum(int p) {
double sum = 0;
for (double a : values()) {
sum += Math.pow(a, p);
}
return sum;
}
/**
* remove all elements whose magnitude is < threshold
*
* @param threshold
*/
public void prune(double threshold) {
for (Iterator<Integer> it = keySet().iterator(); it.hasNext();) {
int key = it.next();
if (Math.abs(get(key)) < threshold) {
it.remove();
}
}
}
}