001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math.linear;
018
019 import java.io.Serializable;
020 import java.lang.reflect.Array;
021
022 import org.apache.commons.math.Field;
023 import org.apache.commons.math.FieldElement;
024 import org.apache.commons.math.MathRuntimeException;
025 import org.apache.commons.math.util.OpenIntToFieldHashMap;
026
027 /**
028 * This class implements the {@link FieldVector} interface with a {@link OpenIntToFieldHashMap} backing store.
029 * @param <T> the type of the field elements
030 * @version $Revision: 922714 $ $Date: 2010-03-13 20:35:14 -0500 (Sat, 13 Mar 2010) $
031 * @since 2.0
032 */
033 public class SparseFieldVector<T extends FieldElement<T>> implements FieldVector<T>, Serializable {
034
035 /**
036 * Serial version id
037 */
038 private static final long serialVersionUID = 7841233292190413362L;
039 /** Field to which the elements belong. */
040 private final Field<T> field;
041 /** Entries of the vector. */
042 private final OpenIntToFieldHashMap<T> entries;
043 /** Dimension of the vector. */
044 private final int virtualSize;
045
046 /**
047 * Build a 0-length vector.
048 * <p>Zero-length vectors may be used to initialize construction of vectors
049 * by data gathering. We start with zero-length and use either the {@link
050 * #SparseFieldVector(SparseFieldVector, int)} constructor
051 * or one of the <code>append</code> method ({@link #append(FieldElement)},
052 * {@link #append(FieldElement[])}, {@link #append(FieldVector)},
053 * {@link #append(SparseFieldVector)}) to gather data into this vector.</p>
054 * @param field field to which the elements belong
055 */
056 public SparseFieldVector(Field<T> field) {
057 this(field, 0);
058 }
059
060
061 /**
062 * Construct a (dimension)-length vector of zeros.
063 * @param field field to which the elements belong
064 * @param dimension Size of the vector
065 */
066 public SparseFieldVector(Field<T> field, int dimension) {
067 this.field = field;
068 virtualSize = dimension;
069 entries = new OpenIntToFieldHashMap<T>(field);
070 }
071
072 /**
073 * Build a resized vector, for use with append.
074 * @param v The original vector
075 * @param resize The amount to resize it
076 */
077 protected SparseFieldVector(SparseFieldVector<T> v, int resize) {
078 field = v.field;
079 virtualSize = v.getDimension() + resize;
080 entries = new OpenIntToFieldHashMap<T>(v.entries);
081 }
082
083
084 /**
085 * Build a vector with known the sparseness (for advanced use only).
086 * @param field field to which the elements belong
087 * @param dimension The size of the vector
088 * @param expectedSize The expected number of non-zero entries
089 */
090 public SparseFieldVector(Field<T> field, int dimension, int expectedSize) {
091 this.field = field;
092 virtualSize = dimension;
093 entries = new OpenIntToFieldHashMap<T>(field,expectedSize);
094 }
095
096 /**
097 * Create from a Field array.
098 * Only non-zero entries will be stored
099 * @param field field to which the elements belong
100 * @param values The set of values to create from
101 */
102 public SparseFieldVector(Field<T> field, T[] values) {
103 this.field = field;
104 virtualSize = values.length;
105 entries = new OpenIntToFieldHashMap<T>(field);
106 for (int key = 0; key < values.length; key++) {
107 T value = values[key];
108 entries.put(key, value);
109 }
110 }
111
112
113
114 /**
115 * Copy constructor.
116 * @param v The instance to copy from
117 */
118 public SparseFieldVector(SparseFieldVector<T> v) {
119 field = v.field;
120 virtualSize = v.getDimension();
121 entries = new OpenIntToFieldHashMap<T>(v.getEntries());
122 }
123
124 /**
125 * Get the entries of this instance.
126 * @return entries of this instance
127 */
128 private OpenIntToFieldHashMap<T> getEntries() {
129 return entries;
130 }
131
132 /**
133 * Optimized method to add sparse vectors.
134 * @param v vector to add
135 * @return The sum of <code>this</code> and <code>v</code>
136 * @throws IllegalArgumentException If the dimensions don't match
137 */
138 public FieldVector<T> add(SparseFieldVector<T> v) throws IllegalArgumentException {
139 checkVectorDimensions(v.getDimension());
140 SparseFieldVector<T> res = (SparseFieldVector<T>)copy();
141 OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator();
142 while (iter.hasNext()) {
143 iter.advance();
144 int key = iter.key();
145 T value = iter.value();
146 if (entries.containsKey(key)) {
147 res.setEntry(key, entries.get(key).add(value));
148 } else {
149 res.setEntry(key, value);
150 }
151 }
152 return res;
153
154 }
155
156
157 /** {@inheritDoc} */
158 public FieldVector<T> add(T[] v) throws IllegalArgumentException {
159 checkVectorDimensions(v.length);
160 SparseFieldVector<T> res = new SparseFieldVector<T>(field,getDimension());
161 for (int i = 0; i < v.length; i++) {
162 res.setEntry(i, v[i].add(getEntry(i)));
163 }
164 return res;
165 }
166
167 /**
168 * Construct a vector by appending a vector to this vector.
169 * @param v vector to append to this one.
170 * @return a new vector
171 */
172 public FieldVector<T> append(SparseFieldVector<T> v) {
173 SparseFieldVector<T> res = new SparseFieldVector<T>(this, v.getDimension());
174 OpenIntToFieldHashMap<T>.Iterator iter = v.entries.iterator();
175 while (iter.hasNext()) {
176 iter.advance();
177 res.setEntry(iter.key() + virtualSize, iter.value());
178 }
179 return res;
180 }
181
182 /** {@inheritDoc} */
183 public FieldVector<T> append(FieldVector<T> v) {
184 if (v instanceof SparseFieldVector<?>) {
185 return append((SparseFieldVector<T>) v);
186 } else {
187 return append(v.toArray());
188 }
189 }
190
191 /** {@inheritDoc} */
192 public FieldVector<T> append(T d) {
193 FieldVector<T> res = new SparseFieldVector<T>(this, 1);
194 res.setEntry(virtualSize, d);
195 return res;
196 }
197
198 /** {@inheritDoc} */
199 public FieldVector<T> append(T[] a) {
200 FieldVector<T> res = new SparseFieldVector<T>(this, a.length);
201 for (int i = 0; i < a.length; i++) {
202 res.setEntry(i + virtualSize, a[i]);
203 }
204 return res;
205 }
206
207 /** {@inheritDoc} */
208 public FieldVector<T> copy() {
209 return new SparseFieldVector<T>(this);
210 }
211
212 /** {@inheritDoc} */
213 public T dotProduct(FieldVector<T> v) throws IllegalArgumentException {
214 checkVectorDimensions(v.getDimension());
215 T res = field.getZero();
216 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
217 while (iter.hasNext()) {
218 iter.advance();
219 res = res.add(v.getEntry(iter.key()).multiply(iter.value()));
220 }
221 return res;
222 }
223
224 /** {@inheritDoc} */
225 public T dotProduct(T[] v) throws IllegalArgumentException {
226 checkVectorDimensions(v.length);
227 T res = field.getZero();
228 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
229 while (iter.hasNext()) {
230 int idx = iter.key();
231 T value = field.getZero();
232 if (idx < v.length) {
233 value = v[idx];
234 }
235 res = res.add(value.multiply(iter.value()));
236 }
237 return res;
238 }
239
240 /** {@inheritDoc} */
241 public FieldVector<T> ebeDivide(FieldVector<T> v)
242 throws IllegalArgumentException {
243 checkVectorDimensions(v.getDimension());
244 SparseFieldVector<T> res = new SparseFieldVector<T>(this);
245 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
246 while (iter.hasNext()) {
247 iter.advance();
248 res.setEntry(iter.key(), iter.value().divide(v.getEntry(iter.key())));
249 }
250 return res;
251 }
252
253 /** {@inheritDoc} */
254 public FieldVector<T> ebeDivide(T[] v) throws IllegalArgumentException {
255 checkVectorDimensions(v.length);
256 SparseFieldVector<T> res = new SparseFieldVector<T>(this);
257 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
258 while (iter.hasNext()) {
259 iter.advance();
260 res.setEntry(iter.key(), iter.value().divide(v[iter.key()]));
261 }
262 return res;
263 }
264
265 /** {@inheritDoc} */
266 public FieldVector<T> ebeMultiply(FieldVector<T> v)throws IllegalArgumentException {
267 checkVectorDimensions(v.getDimension());
268 SparseFieldVector<T> res = new SparseFieldVector<T>(this);
269 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
270 while (iter.hasNext()) {
271 iter.advance();
272 res.setEntry(iter.key(), iter.value().multiply(v.getEntry(iter.key())));
273 }
274 return res;
275 }
276
277 /** {@inheritDoc} */
278 public FieldVector<T> ebeMultiply(T[] v) throws IllegalArgumentException {
279 checkVectorDimensions(v.length);
280 SparseFieldVector<T> res = new SparseFieldVector<T>(this);
281 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
282 while (iter.hasNext()) {
283 iter.advance();
284 res.setEntry(iter.key(), iter.value().multiply(v[iter.key()]));
285 }
286 return res;
287 }
288
289 /** {@inheritDoc} */
290 public T[] getData() {
291 T[] res = buildArray(virtualSize);
292 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
293 while (iter.hasNext()) {
294 iter.advance();
295 res[iter.key()] = iter.value();
296 }
297 return res;
298 }
299
300 /** {@inheritDoc} */
301 public int getDimension() {
302 return virtualSize;
303 }
304
305 /** {@inheritDoc} */
306 public T getEntry(int index) throws MatrixIndexException {
307 checkIndex(index);
308 return entries.get(index);
309 }
310
311 /** {@inheritDoc} */
312 public Field<T> getField() {
313 return field;
314 }
315
316 /** {@inheritDoc} */
317 public FieldVector<T> getSubVector(int index, int n)
318 throws MatrixIndexException {
319 checkIndex(index);
320 checkIndex(index + n - 1);
321 SparseFieldVector<T> res = new SparseFieldVector<T>(field,n);
322 int end = index + n;
323 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
324 while (iter.hasNext()) {
325 iter.advance();
326 int key = iter.key();
327 if (key >= index && key < end) {
328 res.setEntry(key - index, iter.value());
329 }
330 }
331 return res;
332 }
333
334 /** {@inheritDoc} */
335 public FieldVector<T> mapAdd(T d) {
336 return copy().mapAddToSelf(d);
337 }
338
339 /** {@inheritDoc} */
340 public FieldVector<T> mapAddToSelf(T d) {
341 for (int i = 0; i < virtualSize; i++) {
342 setEntry(i, getEntry(i).add(d));
343 }
344 return this;
345 }
346
347 /** {@inheritDoc} */
348 public FieldVector<T> mapDivide(T d) {
349 return copy().mapDivideToSelf(d);
350 }
351
352 /** {@inheritDoc} */
353 public FieldVector<T> mapDivideToSelf(T d) {
354 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
355 while (iter.hasNext()) {
356 iter.advance();
357 entries.put(iter.key(), iter.value().divide(d));
358 }
359 return this;
360 }
361
362 /** {@inheritDoc} */
363 public FieldVector<T> mapInv() {
364 return copy().mapInvToSelf();
365 }
366
367 /** {@inheritDoc} */
368 public FieldVector<T> mapInvToSelf() {
369 for (int i = 0; i < virtualSize; i++) {
370 setEntry(i, field.getOne().divide(getEntry(i)));
371 }
372 return this;
373 }
374
375 /** {@inheritDoc} */
376 public FieldVector<T> mapMultiply(T d) {
377 return copy().mapMultiplyToSelf(d);
378 }
379
380 /** {@inheritDoc} */
381 public FieldVector<T> mapMultiplyToSelf(T d) {
382 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
383 while (iter.hasNext()) {
384 iter.advance();
385 entries.put(iter.key(), iter.value().multiply(d));
386 }
387 return this;
388 }
389
390 /** {@inheritDoc} */
391 public FieldVector<T> mapSubtract(T d) {
392 return copy().mapSubtractToSelf(d);
393 }
394
395 /** {@inheritDoc} */
396 public FieldVector<T> mapSubtractToSelf(T d) {
397 return mapAddToSelf(field.getZero().subtract(d));
398 }
399
400 /**
401 * Optimized method to compute outer product when both vectors are sparse.
402 * @param v vector with which outer product should be computed
403 * @return the square matrix outer product between instance and v
404 * @throws IllegalArgumentException if v is not the same size as {@code this}
405 */
406 public FieldMatrix<T> outerProduct(SparseFieldVector<T> v)
407 throws IllegalArgumentException {
408 checkVectorDimensions(v.getDimension());
409 SparseFieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, virtualSize);
410 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
411 while (iter.hasNext()) {
412 iter.advance();
413 OpenIntToFieldHashMap<T>.Iterator iter2 = v.entries.iterator();
414 while (iter2.hasNext()) {
415 iter2.advance();
416 res.setEntry(iter.key(), iter2.key(), iter.value().multiply(iter2.value()));
417 }
418 }
419 return res;
420 }
421
422 /** {@inheritDoc} */
423 public FieldMatrix<T> outerProduct(T[] v) throws IllegalArgumentException {
424 checkVectorDimensions(v.length);
425 FieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, virtualSize);
426 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
427 while (iter.hasNext()) {
428 iter.advance();
429 int row = iter.key();
430 FieldElement<T>value = iter.value();
431 for (int col = 0; col < virtualSize; col++) {
432 res.setEntry(row, col, value.multiply(v[col]));
433 }
434 }
435 return res;
436 }
437
438 /** {@inheritDoc} */
439 public FieldMatrix<T> outerProduct(FieldVector<T> v)
440 throws IllegalArgumentException {
441 if(v instanceof SparseFieldVector<?>)
442 return outerProduct((SparseFieldVector<T>)v);
443 else
444 return outerProduct(v.toArray());
445 }
446
447 /** {@inheritDoc} */
448 public FieldVector<T> projection(FieldVector<T> v)
449 throws IllegalArgumentException {
450 checkVectorDimensions(v.getDimension());
451 return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
452 }
453
454 /** {@inheritDoc} */
455 public FieldVector<T> projection(T[] v) throws IllegalArgumentException {
456 checkVectorDimensions(v.length);
457 return projection(new SparseFieldVector<T>(field,v));
458 }
459
460 /** {@inheritDoc} */
461 public void set(T value) {
462 for (int i = 0; i < virtualSize; i++) {
463 setEntry(i, value);
464 }
465 }
466
467 /** {@inheritDoc} */
468 public void setEntry(int index, T value) throws MatrixIndexException {
469 checkIndex(index);
470 entries.put(index, value);
471 }
472
473 /** {@inheritDoc} */
474 public void setSubVector(int index, FieldVector<T> v)
475 throws MatrixIndexException {
476 checkIndex(index);
477 checkIndex(index + v.getDimension() - 1);
478 setSubVector(index, v.getData());
479 }
480
481 /** {@inheritDoc} */
482 public void setSubVector(int index, T[] v) throws MatrixIndexException {
483 checkIndex(index);
484 checkIndex(index + v.length - 1);
485 for (int i = 0; i < v.length; i++) {
486 setEntry(i + index, v[i]);
487 }
488
489 }
490
491 /**
492 * Optimized method to subtract SparseRealVectors.
493 * @param v The vector to subtract from <code>this</code>
494 * @return The difference of <code>this</code> and <code>v</code>
495 * @throws IllegalArgumentException If the dimensions don't match
496 */
497 public SparseFieldVector<T> subtract(SparseFieldVector<T> v) throws IllegalArgumentException{
498 checkVectorDimensions(v.getDimension());
499 SparseFieldVector<T> res = (SparseFieldVector<T>)copy();
500 OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator();
501 while (iter.hasNext()) {
502 iter.advance();
503 int key = iter.key();
504 if (entries.containsKey(key)) {
505 res.setEntry(key, entries.get(key).subtract(iter.value()));
506 } else {
507 res.setEntry(key, field.getZero().subtract(iter.value()));
508 }
509 }
510 return res;
511 }
512
513 /** {@inheritDoc} */
514 public FieldVector<T> subtract(FieldVector<T> v)
515 throws IllegalArgumentException {
516 if(v instanceof SparseFieldVector<?>)
517 return subtract((SparseFieldVector<T>)v);
518 else
519 return subtract(v.toArray());
520 }
521
522 /** {@inheritDoc} */
523 public FieldVector<T> subtract(T[] v) throws IllegalArgumentException {
524 checkVectorDimensions(v.length);
525 SparseFieldVector<T> res = new SparseFieldVector<T>(this);
526 for (int i = 0; i < v.length; i++) {
527 if (entries.containsKey(i)) {
528 res.setEntry(i, entries.get(i).subtract(v[i]));
529 } else {
530 res.setEntry(i, field.getZero().subtract(v[i]));
531 }
532 }
533 return res;
534 }
535
536 /** {@inheritDoc} */
537 public T[] toArray() {
538 return getData();
539 }
540
541 /**
542 * Check if an index is valid.
543 *
544 * @param index
545 * index to check
546 * @exception MatrixIndexException
547 * if index is not valid
548 */
549 private void checkIndex(final int index) throws MatrixIndexException {
550 if (index < 0 || index >= getDimension()) {
551 throw new MatrixIndexException(
552 "index {0} out of allowed range [{1}, {2}]",
553 index, 0, getDimension() - 1);
554 }
555 }
556
557 /**
558 * Check if instance dimension is equal to some expected value.
559 *
560 * @param n
561 * expected dimension.
562 * @exception IllegalArgumentException
563 * if the dimension is inconsistent with vector size
564 */
565 protected void checkVectorDimensions(int n) throws IllegalArgumentException {
566 if (getDimension() != n) {
567 throw MathRuntimeException.createIllegalArgumentException(
568 "vector length mismatch: got {0} but expected {1}",
569 getDimension(), n);
570 }
571 }
572
573
574 /** {@inheritDoc} */
575 public FieldVector<T> add(FieldVector<T> v) throws IllegalArgumentException {
576 if (v instanceof SparseFieldVector<?>) {
577 return add((SparseFieldVector<T>)v);
578 } else {
579 return add(v.toArray());
580 }
581 }
582
583 /** Build an array of elements.
584 * @param length size of the array to build
585 * @return a new array
586 */
587 @SuppressWarnings("unchecked") // field is type T
588 private T[] buildArray(final int length) {
589 return (T[]) Array.newInstance(field.getZero().getClass(), length);
590 }
591
592
593 /** {@inheritDoc} */
594 @Override
595 public int hashCode() {
596 final int prime = 31;
597 int result = 1;
598 result = prime * result + ((field == null) ? 0 : field.hashCode());
599 result = prime * result + virtualSize;
600 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
601 while (iter.hasNext()) {
602 iter.advance();
603 int temp = iter.value().hashCode();
604 result = prime * result + temp;
605 }
606 return result;
607 }
608
609
610 /** {@inheritDoc} */
611 @Override
612 public boolean equals(Object obj) {
613
614 if (this == obj) {
615 return true;
616 }
617
618 if (!(obj instanceof SparseFieldVector<?>)) {
619 return false;
620 }
621
622 @SuppressWarnings("unchecked") // OK, because "else if" check below ensures that
623 // other must be the same type as this
624 SparseFieldVector<T> other = (SparseFieldVector<T>) obj;
625 if (field == null) {
626 if (other.field != null) {
627 return false;
628 }
629 } else if (!field.equals(other.field)) {
630 return false;
631 }
632 if (virtualSize != other.virtualSize) {
633 return false;
634 }
635
636 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
637 while (iter.hasNext()) {
638 iter.advance();
639 T test = other.getEntry(iter.key());
640 if (!test.equals(iter.value())) {
641 return false;
642 }
643 }
644 iter = other.getEntries().iterator();
645 while (iter.hasNext()) {
646 iter.advance();
647 T test = iter.value();
648 if (!test.equals(getEntry(iter.key()))) {
649 return false;
650 }
651 }
652 return true;
653 }
654
655
656
657 }