001/* 002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences. 003 * Copyright (C) 2007 - JScience (http://jscience.org/) 004 * All rights reserved. 005 * 006 * Permission to use, copy, modify, and distribute this software is 007 * freely granted, provided that this notice is preserved. 008 */ 009package org.jscience.mathematics.vector; 010 011import java.util.Map; 012 013import javolution.context.ObjectFactory; 014import javolution.util.FastComparator; 015import javolution.util.FastMap; 016import javolution.util.Index; 017import javolution.xml.XMLFormat; 018import javolution.xml.stream.XMLStreamException; 019 020import org.jscience.mathematics.structure.Field; 021 022/** 023 * <p> This class represents a sparse vector.</p> 024 * <p> Sparse vectors can be created using an index-to-element mapping or 025 * by adding single elements sparse vectors together.</p> 026 * 027 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 028 * @version 3.3, January 2, 2007 029 */ 030public final class SparseVector<F extends Field<F>> extends Vector<F> { 031 032 /** 033 * Holds the default XML representation for sparse vectors. 034 * For example:[code] 035 * <SparseVector dimension="16"> 036 * <Zero class="Complex" real="0.0" imaginary="0.0" /> 037 * <Elements> 038 * <Index value="4" /> 039 * <Complex real="1.0" imaginary="0.0" /> 040 * <Index value="6" /> 041 * <Complex real="0.0" imaginary="1.0" /> 042 * </Elements> 043 * </SparseVector>[/code] 044 */ 045 protected static final XMLFormat<SparseVector> XML = new XMLFormat<SparseVector>( 046 SparseVector.class) { 047 048 @Override 049 public SparseVector newInstance(Class<SparseVector> cls, InputElement xml) 050 throws XMLStreamException { 051 return FACTORY.object(); 052 } 053 054 @SuppressWarnings("unchecked") 055 @Override 056 public void read(InputElement xml, SparseVector V) 057 throws XMLStreamException { 058 V._dimension = xml.getAttribute("dimension", 0); 059 V._zero = xml.get("Zero"); 060 V._elements.putAll(xml.get("Elements", FastMap.class)); 061 } 062 063 @Override 064 public void write(SparseVector V, OutputElement xml) 065 throws XMLStreamException { 066 xml.setAttribute("dimension", V._dimension); 067 xml.add(V._zero, "Zero"); 068 xml.add(V._elements, "Elements", FastMap.class); 069 } 070 }; 071 072 /** 073 * Holds this vector dimension. 074 */ 075 int _dimension; 076 077 /** 078 * Holds zero. 079 */ 080 F _zero; 081 082 /** 083 * Holds the index to element mapping. 084 */ 085 final FastMap<Index, F> _elements = new FastMap<Index, F>(); 086 087 /** 088 * Returns a sparse vector having a single element at the specified index. 089 * 090 * @param dimension this vector dimension. 091 * @param zero the element representing zero. 092 * @param i the index value of this vector single element. 093 * @param element the element at the specified index. 094 * @return the corresponding vector. 095 */ 096 public static <F extends Field<F>> SparseVector<F> valueOf(int dimension, 097 F zero, int i, F element) { 098 SparseVector<F> V = SparseVector.newInstance(dimension, zero); 099 V._elements.put(Index.valueOf(i), element); 100 return V; 101 } 102 103 /** 104 * Returns a sparse vector from the specified index to element mapping. 105 * 106 * @param dimension this vector dimension. 107 * @param zero the element representing zero. 108 * @param elements the index to element mapping. 109 * @return the corresponding vector. 110 */ 111 public static <F extends Field<F>> SparseVector<F> valueOf(int dimension, 112 F zero, Map<Index, F> elements) { 113 SparseVector<F> V = SparseVector.newInstance(dimension, zero); 114 V._elements.putAll(elements); 115 return V; 116 } 117 118 /** 119 * Returns a sparse vector equivalent to the specified vector but with 120 * the zero elements removed removed using a default object equality 121 * comparator. 122 * 123 * @param that the vector to convert. 124 * @param zero the zero element for the sparse vector to return. 125 * @return <code>SparseVector.valueOf(that, zero, FastComparator.DEFAULT)</code> 126 */ 127 public static <F extends Field<F>> SparseVector<F> valueOf( 128 Vector<F> that, F zero) { 129 return SparseVector.valueOf(that, zero, FastComparator.DEFAULT); 130 } 131 132 /** 133 * Returns a sparse vector equivalent to the specified vector but with 134 * the zero elements removed using the specified object equality comparator. 135 * This method can be used to clean up sparse vectors (to remove elements 136 * close to zero). 137 * 138 * @param that the vector to convert. 139 * @param zero the zero element for the sparse vector to return. 140 * @param comparator the comparator used to determinate zero equality. 141 * @return a sparse vector with zero elements removed. 142 */ 143 public static <F extends Field<F>> SparseVector<F> valueOf( 144 Vector<F> that, F zero, FastComparator<? super F> comparator) { 145 if (that instanceof SparseVector) 146 return SparseVector.valueOf((SparseVector<F>) that, zero, comparator); 147 int n = that.getDimension(); 148 SparseVector<F> V = SparseVector.newInstance(n, zero); 149 for (int i=0; i < n; i++) { 150 F element = that.get(i); 151 if (!comparator.areEqual(zero, element)) { 152 V._elements.put(Index.valueOf(i), element); 153 } 154 } 155 return V; 156 } 157 private static <F extends Field<F>> SparseVector<F> valueOf( 158 SparseVector<F> that, F zero, FastComparator<? super F> comparator) { 159 SparseVector<F> V = SparseVector.newInstance(that._dimension, zero); 160 for (FastMap.Entry<Index, F> e = that._elements.head(), n = that._elements.tail(); (e = e 161 .getNext()) != n;) { 162 if (!comparator.areEqual(e.getValue(), zero)) { 163 V._elements.put(e.getKey(), e.getValue()); 164 } 165 } 166 return V; 167 } 168 169 /** 170 * Returns the value of the non-set elements for this sparse vector. 171 * 172 * @return the element corresponding to zero. 173 */ 174 public F getZero() { 175 return _zero; 176 } 177 178 @Override 179 public int getDimension() { 180 return _dimension; 181 } 182 183 @Override 184 public F get(int i) { 185 if ((i < 0) || (i >= _dimension)) 186 throw new IndexOutOfBoundsException(); 187 F element = _elements.get(Index.valueOf(i)); 188 return (element == null) ? _zero : element; 189 } 190 191 @Override 192 public SparseVector<F> opposite() { 193 SparseVector<F> V = SparseVector.newInstance(_dimension, _zero); 194 for (FastMap.Entry<Index, F> e = _elements.head(), n = _elements.tail(); (e = e 195 .getNext()) != n;) { 196 V._elements.put(e.getKey(), e.getValue().opposite()); 197 } 198 return V; 199 } 200 201 @Override 202 public SparseVector<F> plus(Vector<F> that) { 203 if (that instanceof SparseVector) 204 return plus((SparseVector<F>) that); 205 return plus(SparseVector.valueOf(that, _zero, FastComparator.DEFAULT)); 206 } 207 208 private SparseVector<F> plus(SparseVector<F> that) { 209 if (this._dimension != that._dimension) throw new DimensionException(); 210 SparseVector<F> V = SparseVector.newInstance(_dimension, _zero); 211 V._elements.putAll(this._elements); 212 for (FastMap.Entry<Index, F> e = that._elements.head(), n = that._elements.tail(); 213 (e = e.getNext()) != n;) { 214 Index index = e.getKey(); 215 FastMap.Entry<Index, F> entry = V._elements.getEntry(index); 216 if (entry == null) { 217 V._elements.put(index, e.getValue()); 218 } else { 219 entry.setValue(entry.getValue().plus(e.getValue())); 220 } 221 } 222 return V; 223 } 224 225 @Override 226 public SparseVector<F> times(F k) { 227 SparseVector<F> V = SparseVector.newInstance(_dimension, _zero); 228 for (FastMap.Entry<Index, F> e = _elements.head(), n = _elements.tail(); (e = e 229 .getNext()) != n;) { 230 V._elements.put(e.getKey(), e.getValue().times(k)); 231 } 232 return V; 233 } 234 235 @Override 236 public F times(Vector<F> that) { 237 if (that.getDimension() != _dimension) 238 throw new DimensionException(); 239 F sum = null; 240 for (FastMap.Entry<Index, F> e = _elements.head(), n = _elements.tail(); (e = e 241 .getNext()) != n;) { 242 F f = e.getValue().times(that.get(e.getKey().intValue())); 243 sum = (sum == null) ? f : sum.plus(f); 244 } 245 return (sum != null) ? sum : _zero; 246 } 247 248 @SuppressWarnings("unchecked") 249 @Override 250 public SparseVector<F> copy() { 251 SparseVector<F> V = SparseVector.newInstance(_dimension, (F)_zero.copy()); 252 for (Map.Entry<Index, F> e : _elements.entrySet()) { 253 V._elements.put(e.getKey(), (F) e.getValue().copy()); 254 } 255 return V; 256 } 257 258 /////////////////////// 259 // Factory creation. // 260 /////////////////////// 261 262 @SuppressWarnings("unchecked") 263 static <F extends Field<F>> SparseVector<F> newInstance(int dimension, F zero) { 264 SparseVector<F> V = FACTORY.object(); 265 V._dimension = dimension; 266 V._zero = zero; 267 return V; 268 } 269 270 private static final ObjectFactory<SparseVector> FACTORY = new ObjectFactory<SparseVector>() { 271 @Override 272 protected SparseVector create() { 273 return new SparseVector(); 274 } 275 276 @Override 277 protected void cleanup(SparseVector vector) { 278 vector._elements.reset(); 279 } 280 }; 281 282 private SparseVector() { 283 } 284 285 private static final long serialVersionUID = 1L; 286 287}