org.jscience.mathematics.vector.SparseVector Maven / Gradle / Ivy
The newest version!
/*
* JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
* Copyright (C) 2007 - JScience (http://jscience.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package org.jscience.mathematics.vector;
import java.util.Map;
import javolution.context.ObjectFactory;
import javolution.util.FastComparator;
import javolution.util.FastMap;
import javolution.util.Index;
import javolution.xml.XMLFormat;
import javolution.xml.stream.XMLStreamException;
import org.jscience.mathematics.structure.Field;
/**
* This class represents a sparse vector.
* Sparse vectors can be created using an index-to-element mapping or
* by adding single elements sparse vectors together.
*
* @author Jean-Marie Dautelle
* @version 3.3, January 2, 2007
*/
public final class SparseVector> extends Vector {
/**
* Holds the default XML representation for sparse vectors.
* For example:[code]
*
*
*
*
*
*
*
*
* [/code]
*/
protected static final XMLFormat XML = new XMLFormat(
SparseVector.class) {
@Override
public SparseVector newInstance(Class cls, InputElement xml)
throws XMLStreamException {
return FACTORY.object();
}
@SuppressWarnings("unchecked")
@Override
public void read(InputElement xml, SparseVector V)
throws XMLStreamException {
V._dimension = xml.getAttribute("dimension", 0);
V._zero = xml.get("Zero");
V._elements.putAll(xml.get("Elements", FastMap.class));
}
@Override
public void write(SparseVector V, OutputElement xml)
throws XMLStreamException {
xml.setAttribute("dimension", V._dimension);
xml.add(V._zero, "Zero");
xml.add(V._elements, "Elements", FastMap.class);
}
};
/**
* Holds this vector dimension.
*/
int _dimension;
/**
* Holds zero.
*/
F _zero;
/**
* Holds the index to element mapping.
*/
final FastMap _elements = new FastMap();
/**
* Returns a sparse vector having a single element at the specified index.
*
* @param dimension this vector dimension.
* @param zero the element representing zero.
* @param i the index value of this vector single element.
* @param element the element at the specified index.
* @return the corresponding vector.
*/
public static > SparseVector valueOf(int dimension,
F zero, int i, F element) {
SparseVector V = SparseVector.newInstance(dimension, zero);
V._elements.put(Index.valueOf(i), element);
return V;
}
/**
* Returns a sparse vector from the specified index to element mapping.
*
* @param dimension this vector dimension.
* @param zero the element representing zero.
* @param elements the index to element mapping.
* @return the corresponding vector.
*/
public static > SparseVector valueOf(int dimension,
F zero, Map elements) {
SparseVector V = SparseVector.newInstance(dimension, zero);
V._elements.putAll(elements);
return V;
}
/**
* Returns a sparse vector equivalent to the specified vector but with
* the zero elements removed removed using a default object equality
* comparator.
*
* @param that the vector to convert.
* @param zero the zero element for the sparse vector to return.
* @return SparseVector.valueOf(that, zero, FastComparator.DEFAULT)
*/
public static > SparseVector valueOf(
Vector that, F zero) {
return SparseVector.valueOf(that, zero, FastComparator.DEFAULT);
}
/**
* Returns a sparse vector equivalent to the specified vector but with
* the zero elements removed using the specified object equality comparator.
* This method can be used to clean up sparse vectors (to remove elements
* close to zero).
*
* @param that the vector to convert.
* @param zero the zero element for the sparse vector to return.
* @param comparator the comparator used to determinate zero equality.
* @return a sparse vector with zero elements removed.
*/
public static > SparseVector valueOf(
Vector that, F zero, FastComparator comparator) {
if (that instanceof SparseVector)
return SparseVector.valueOf((SparseVector) that, zero, comparator);
int n = that.getDimension();
SparseVector V = SparseVector.newInstance(n, zero);
for (int i=0; i < n; i++) {
F element = that.get(i);
if (!comparator.areEqual(zero, element)) {
V._elements.put(Index.valueOf(i), element);
}
}
return V;
}
private static > SparseVector valueOf(
SparseVector that, F zero, FastComparator comparator) {
SparseVector V = SparseVector.newInstance(that._dimension, zero);
for (FastMap.Entry e = that._elements.head(), n = that._elements.tail(); (e = e
.getNext()) != n;) {
if (!comparator.areEqual(e.getValue(), zero)) {
V._elements.put(e.getKey(), e.getValue());
}
}
return V;
}
/**
* Returns the value of the non-set elements for this sparse vector.
*
* @return the element corresponding to zero.
*/
public F getZero() {
return _zero;
}
@Override
public int getDimension() {
return _dimension;
}
@Override
public F get(int i) {
if ((i < 0) || (i >= _dimension))
throw new IndexOutOfBoundsException();
F element = _elements.get(Index.valueOf(i));
return (element == null) ? _zero : element;
}
@Override
public SparseVector opposite() {
SparseVector V = SparseVector.newInstance(_dimension, _zero);
for (FastMap.Entry e = _elements.head(), n = _elements.tail(); (e = e
.getNext()) != n;) {
V._elements.put(e.getKey(), e.getValue().opposite());
}
return V;
}
@Override
public SparseVector plus(Vector that) {
if (that instanceof SparseVector)
return plus((SparseVector) that);
return plus(SparseVector.valueOf(that, _zero, FastComparator.DEFAULT));
}
private SparseVector plus(SparseVector that) {
if (this._dimension != that._dimension) throw new DimensionException();
SparseVector V = SparseVector.newInstance(_dimension, _zero);
V._elements.putAll(this._elements);
for (FastMap.Entry e = that._elements.head(), n = that._elements.tail();
(e = e.getNext()) != n;) {
Index index = e.getKey();
FastMap.Entry entry = V._elements.getEntry(index);
if (entry == null) {
V._elements.put(index, e.getValue());
} else {
entry.setValue(entry.getValue().plus(e.getValue()));
}
}
return V;
}
@Override
public SparseVector times(F k) {
SparseVector V = SparseVector.newInstance(_dimension, _zero);
for (FastMap.Entry e = _elements.head(), n = _elements.tail(); (e = e
.getNext()) != n;) {
V._elements.put(e.getKey(), e.getValue().times(k));
}
return V;
}
@Override
public F times(Vector that) {
if (that.getDimension() != _dimension)
throw new DimensionException();
F sum = null;
for (FastMap.Entry e = _elements.head(), n = _elements.tail(); (e = e
.getNext()) != n;) {
F f = e.getValue().times(that.get(e.getKey().intValue()));
sum = (sum == null) ? f : sum.plus(f);
}
return (sum != null) ? sum : _zero;
}
@SuppressWarnings("unchecked")
@Override
public SparseVector copy() {
SparseVector V = SparseVector.newInstance(_dimension, (F)_zero.copy());
for (Map.Entry e : _elements.entrySet()) {
V._elements.put(e.getKey(), (F) e.getValue().copy());
}
return V;
}
///////////////////////
// Factory creation. //
///////////////////////
@SuppressWarnings("unchecked")
static > SparseVector newInstance(int dimension, F zero) {
SparseVector V = FACTORY.object();
V._dimension = dimension;
V._zero = zero;
return V;
}
private static final ObjectFactory FACTORY = new ObjectFactory() {
@Override
protected SparseVector create() {
return new SparseVector();
}
@Override
protected void cleanup(SparseVector vector) {
vector._elements.reset();
}
};
private SparseVector() {
}
private static final long serialVersionUID = 1L;
}