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.math3.linear; 018 019 import java.io.Serializable; 020 import java.lang.reflect.Array; 021 022 import org.apache.commons.math3.Field; 023 import org.apache.commons.math3.FieldElement; 024 import org.apache.commons.math3.exception.MathArithmeticException; 025 import org.apache.commons.math3.exception.NotPositiveException; 026 import org.apache.commons.math3.exception.NullArgumentException; 027 import org.apache.commons.math3.exception.OutOfRangeException; 028 import org.apache.commons.math3.exception.DimensionMismatchException; 029 import org.apache.commons.math3.exception.util.LocalizedFormats; 030 import org.apache.commons.math3.util.OpenIntToFieldHashMap; 031 032 /** 033 * This class implements the {@link FieldVector} interface with a {@link OpenIntToFieldHashMap} backing store. 034 * @param <T> the type of the field elements 035 * @version $Id: SparseFieldVector.java 1416643 2012-12-03 19:37:14Z tn $ 036 * @since 2.0 037 * @deprecated As of version 3.1, this class is deprecated, for reasons exposed 038 * in this JIRA 039 * <a href="https://issues.apache.org/jira/browse/MATH-870">ticket</a>. This 040 * class will be removed in version 4.0. 041 */ 042 @Deprecated 043 public class SparseFieldVector<T extends FieldElement<T>> implements FieldVector<T>, Serializable { 044 /** Serialization identifier. */ 045 private static final long serialVersionUID = 7841233292190413362L; 046 /** Field to which the elements belong. */ 047 private final Field<T> field; 048 /** Entries of the vector. */ 049 private final OpenIntToFieldHashMap<T> entries; 050 /** Dimension of the vector. */ 051 private final int virtualSize; 052 053 /** 054 * Build a 0-length vector. 055 * Zero-length vectors may be used to initialize construction of vectors 056 * by data gathering. We start with zero-length and use either the {@link 057 * #SparseFieldVector(SparseFieldVector, int)} constructor 058 * or one of the {@code append} method ({@link #append(FieldVector)} or 059 * {@link #append(SparseFieldVector)}) to gather data into this vector. 060 * 061 * @param field Field to which the elements belong. 062 */ 063 public SparseFieldVector(Field<T> field) { 064 this(field, 0); 065 } 066 067 068 /** 069 * Construct a vector of zeroes. 070 * 071 * @param field Field to which the elements belong. 072 * @param dimension Size of the vector. 073 */ 074 public SparseFieldVector(Field<T> field, int dimension) { 075 this.field = field; 076 virtualSize = dimension; 077 entries = new OpenIntToFieldHashMap<T>(field); 078 } 079 080 /** 081 * Build a resized vector, for use with append. 082 * 083 * @param v Original vector 084 * @param resize Amount to add. 085 */ 086 protected SparseFieldVector(SparseFieldVector<T> v, int resize) { 087 field = v.field; 088 virtualSize = v.getDimension() + resize; 089 entries = new OpenIntToFieldHashMap<T>(v.entries); 090 } 091 092 093 /** 094 * Build a vector with known the sparseness (for advanced use only). 095 * 096 * @param field Field to which the elements belong. 097 * @param dimension Size of the vector. 098 * @param expectedSize Expected number of non-zero entries. 099 */ 100 public SparseFieldVector(Field<T> field, int dimension, int expectedSize) { 101 this.field = field; 102 virtualSize = dimension; 103 entries = new OpenIntToFieldHashMap<T>(field,expectedSize); 104 } 105 106 /** 107 * Create from a Field array. 108 * Only non-zero entries will be stored. 109 * 110 * @param field Field to which the elements belong. 111 * @param values Set of values to create from. 112 */ 113 public SparseFieldVector(Field<T> field, T[] values) { 114 this.field = field; 115 virtualSize = values.length; 116 entries = new OpenIntToFieldHashMap<T>(field); 117 for (int key = 0; key < values.length; key++) { 118 T value = values[key]; 119 entries.put(key, value); 120 } 121 } 122 123 /** 124 * Copy constructor. 125 * 126 * @param v Instance to copy. 127 */ 128 public SparseFieldVector(SparseFieldVector<T> v) { 129 field = v.field; 130 virtualSize = v.getDimension(); 131 entries = new OpenIntToFieldHashMap<T>(v.getEntries()); 132 } 133 134 /** 135 * Get the entries of this instance. 136 * 137 * @return the entries of this instance 138 */ 139 private OpenIntToFieldHashMap<T> getEntries() { 140 return entries; 141 } 142 143 /** 144 * Optimized method to add sparse vectors. 145 * 146 * @param v Vector to add. 147 * @return {@code this + v}. 148 * @throws DimensionMismatchException if {@code v} is not the same size as 149 * {@code this}. 150 */ 151 public FieldVector<T> add(SparseFieldVector<T> v) 152 throws DimensionMismatchException { 153 checkVectorDimensions(v.getDimension()); 154 SparseFieldVector<T> res = (SparseFieldVector<T>)copy(); 155 OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator(); 156 while (iter.hasNext()) { 157 iter.advance(); 158 int key = iter.key(); 159 T value = iter.value(); 160 if (entries.containsKey(key)) { 161 res.setEntry(key, entries.get(key).add(value)); 162 } else { 163 res.setEntry(key, value); 164 } 165 } 166 return res; 167 168 } 169 170 /** 171 * Construct a vector by appending a vector to this vector. 172 * 173 * @param v Vector to append to this one. 174 * @return a new vector. 175 */ 176 public FieldVector<T> append(SparseFieldVector<T> v) { 177 SparseFieldVector<T> res = new SparseFieldVector<T>(this, v.getDimension()); 178 OpenIntToFieldHashMap<T>.Iterator iter = v.entries.iterator(); 179 while (iter.hasNext()) { 180 iter.advance(); 181 res.setEntry(iter.key() + virtualSize, iter.value()); 182 } 183 return res; 184 } 185 186 /** {@inheritDoc} */ 187 public FieldVector<T> append(FieldVector<T> v) { 188 if (v instanceof SparseFieldVector<?>) { 189 return append((SparseFieldVector<T>) v); 190 } else { 191 final int n = v.getDimension(); 192 FieldVector<T> res = new SparseFieldVector<T>(this, n); 193 for (int i = 0; i < n; i++) { 194 res.setEntry(i + virtualSize, v.getEntry(i)); 195 } 196 return res; 197 } 198 } 199 200 /** {@inheritDoc} */ 201 public FieldVector<T> append(T d) { 202 FieldVector<T> res = new SparseFieldVector<T>(this, 1); 203 res.setEntry(virtualSize, d); 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 DimensionMismatchException { 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 FieldVector<T> ebeDivide(FieldVector<T> v) 226 throws DimensionMismatchException, MathArithmeticException { 227 checkVectorDimensions(v.getDimension()); 228 SparseFieldVector<T> res = new SparseFieldVector<T>(this); 229 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator(); 230 while (iter.hasNext()) { 231 iter.advance(); 232 res.setEntry(iter.key(), iter.value().divide(v.getEntry(iter.key()))); 233 } 234 return res; 235 } 236 237 /** {@inheritDoc} */ 238 public FieldVector<T> ebeMultiply(FieldVector<T> v) 239 throws DimensionMismatchException { 240 checkVectorDimensions(v.getDimension()); 241 SparseFieldVector<T> res = new SparseFieldVector<T>(this); 242 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator(); 243 while (iter.hasNext()) { 244 iter.advance(); 245 res.setEntry(iter.key(), iter.value().multiply(v.getEntry(iter.key()))); 246 } 247 return res; 248 } 249 250 /** 251 * {@inheritDoc} 252 * 253 * @deprecated as of 3.1, to be removed in 4.0. Please use the {@link #toArray()} method instead. 254 */ 255 @Deprecated 256 public T[] getData() { 257 return toArray(); 258 } 259 260 /** {@inheritDoc} */ 261 public int getDimension() { 262 return virtualSize; 263 } 264 265 /** {@inheritDoc} */ 266 public T getEntry(int index) throws OutOfRangeException { 267 checkIndex(index); 268 return entries.get(index); 269 } 270 271 /** {@inheritDoc} */ 272 public Field<T> getField() { 273 return field; 274 } 275 276 /** {@inheritDoc} */ 277 public FieldVector<T> getSubVector(int index, int n) 278 throws OutOfRangeException, NotPositiveException { 279 if (n < 0) { 280 throw new NotPositiveException(LocalizedFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, n); 281 } 282 checkIndex(index); 283 checkIndex(index + n - 1); 284 SparseFieldVector<T> res = new SparseFieldVector<T>(field,n); 285 int end = index + n; 286 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 287 while (iter.hasNext()) { 288 iter.advance(); 289 int key = iter.key(); 290 if (key >= index && key < end) { 291 res.setEntry(key - index, iter.value()); 292 } 293 } 294 return res; 295 } 296 297 /** {@inheritDoc} */ 298 public FieldVector<T> mapAdd(T d) throws NullArgumentException { 299 return copy().mapAddToSelf(d); 300 } 301 302 /** {@inheritDoc} */ 303 public FieldVector<T> mapAddToSelf(T d) throws NullArgumentException { 304 for (int i = 0; i < virtualSize; i++) { 305 setEntry(i, getEntry(i).add(d)); 306 } 307 return this; 308 } 309 310 /** {@inheritDoc} */ 311 public FieldVector<T> mapDivide(T d) 312 throws NullArgumentException, MathArithmeticException { 313 return copy().mapDivideToSelf(d); 314 } 315 316 /** {@inheritDoc} */ 317 public FieldVector<T> mapDivideToSelf(T d) 318 throws NullArgumentException, MathArithmeticException { 319 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 320 while (iter.hasNext()) { 321 iter.advance(); 322 entries.put(iter.key(), iter.value().divide(d)); 323 } 324 return this; 325 } 326 327 /** {@inheritDoc} */ 328 public FieldVector<T> mapInv() throws MathArithmeticException { 329 return copy().mapInvToSelf(); 330 } 331 332 /** {@inheritDoc} */ 333 public FieldVector<T> mapInvToSelf() throws MathArithmeticException { 334 for (int i = 0; i < virtualSize; i++) { 335 setEntry(i, field.getOne().divide(getEntry(i))); 336 } 337 return this; 338 } 339 340 /** {@inheritDoc} */ 341 public FieldVector<T> mapMultiply(T d) throws NullArgumentException { 342 return copy().mapMultiplyToSelf(d); 343 } 344 345 /** {@inheritDoc} */ 346 public FieldVector<T> mapMultiplyToSelf(T d) throws NullArgumentException { 347 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 348 while (iter.hasNext()) { 349 iter.advance(); 350 entries.put(iter.key(), iter.value().multiply(d)); 351 } 352 return this; 353 } 354 355 /** {@inheritDoc} */ 356 public FieldVector<T> mapSubtract(T d) throws NullArgumentException { 357 return copy().mapSubtractToSelf(d); 358 } 359 360 /** {@inheritDoc} */ 361 public FieldVector<T> mapSubtractToSelf(T d) throws NullArgumentException { 362 return mapAddToSelf(field.getZero().subtract(d)); 363 } 364 365 /** 366 * Optimized method to compute outer product when both vectors are sparse. 367 * @param v vector with which outer product should be computed 368 * @return the matrix outer product between instance and v 369 */ 370 public FieldMatrix<T> outerProduct(SparseFieldVector<T> v) { 371 final int n = v.getDimension(); 372 SparseFieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, n); 373 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 374 while (iter.hasNext()) { 375 iter.advance(); 376 OpenIntToFieldHashMap<T>.Iterator iter2 = v.entries.iterator(); 377 while (iter2.hasNext()) { 378 iter2.advance(); 379 res.setEntry(iter.key(), iter2.key(), iter.value().multiply(iter2.value())); 380 } 381 } 382 return res; 383 } 384 385 /** {@inheritDoc} */ 386 public FieldMatrix<T> outerProduct(FieldVector<T> v) { 387 if (v instanceof SparseFieldVector<?>) { 388 return outerProduct((SparseFieldVector<T>)v); 389 } else { 390 final int n = v.getDimension(); 391 FieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, n); 392 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 393 while (iter.hasNext()) { 394 iter.advance(); 395 int row = iter.key(); 396 FieldElement<T>value = iter.value(); 397 for (int col = 0; col < n; col++) { 398 res.setEntry(row, col, value.multiply(v.getEntry(col))); 399 } 400 } 401 return res; 402 } 403 } 404 405 /** {@inheritDoc} */ 406 public FieldVector<T> projection(FieldVector<T> v) 407 throws DimensionMismatchException, MathArithmeticException { 408 checkVectorDimensions(v.getDimension()); 409 return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v))); 410 } 411 412 /** {@inheritDoc} */ 413 public void set(T value) { 414 for (int i = 0; i < virtualSize; i++) { 415 setEntry(i, value); 416 } 417 } 418 419 /** {@inheritDoc} */ 420 public void setEntry(int index, T value) throws OutOfRangeException { 421 checkIndex(index); 422 entries.put(index, value); 423 } 424 425 /** {@inheritDoc} */ 426 public void setSubVector(int index, FieldVector<T> v) 427 throws OutOfRangeException { 428 checkIndex(index); 429 checkIndex(index + v.getDimension() - 1); 430 final int n = v.getDimension(); 431 for (int i = 0; i < n; i++) { 432 setEntry(i + index, v.getEntry(i)); 433 } 434 } 435 436 /** 437 * Optimized method to compute {@code this} minus {@code v}. 438 * @param v vector to be subtracted 439 * @return {@code this - v} 440 * @throws DimensionMismatchException if {@code v} is not the same size as 441 * {@code this}. 442 */ 443 public SparseFieldVector<T> subtract(SparseFieldVector<T> v) 444 throws DimensionMismatchException { 445 checkVectorDimensions(v.getDimension()); 446 SparseFieldVector<T> res = (SparseFieldVector<T>)copy(); 447 OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator(); 448 while (iter.hasNext()) { 449 iter.advance(); 450 int key = iter.key(); 451 if (entries.containsKey(key)) { 452 res.setEntry(key, entries.get(key).subtract(iter.value())); 453 } else { 454 res.setEntry(key, field.getZero().subtract(iter.value())); 455 } 456 } 457 return res; 458 } 459 460 /** {@inheritDoc} */ 461 public FieldVector<T> subtract(FieldVector<T> v) 462 throws DimensionMismatchException { 463 if (v instanceof SparseFieldVector<?>) { 464 return subtract((SparseFieldVector<T>)v); 465 } else { 466 final int n = v.getDimension(); 467 checkVectorDimensions(n); 468 SparseFieldVector<T> res = new SparseFieldVector<T>(this); 469 for (int i = 0; i < n; i++) { 470 if (entries.containsKey(i)) { 471 res.setEntry(i, entries.get(i).subtract(v.getEntry(i))); 472 } else { 473 res.setEntry(i, field.getZero().subtract(v.getEntry(i))); 474 } 475 } 476 return res; 477 } 478 } 479 480 /** {@inheritDoc} */ 481 public T[] toArray() { 482 T[] res = buildArray(virtualSize); 483 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 484 while (iter.hasNext()) { 485 iter.advance(); 486 res[iter.key()] = iter.value(); 487 } 488 return res; 489 } 490 491 /** 492 * Check whether an index is valid. 493 * 494 * @param index Index to check. 495 * @throws OutOfRangeException if the index is not valid. 496 */ 497 private void checkIndex(final int index) throws OutOfRangeException { 498 if (index < 0 || index >= getDimension()) { 499 throw new OutOfRangeException(index, 0, getDimension() - 1); 500 } 501 } 502 503 /** 504 * Check if instance dimension is equal to some expected value. 505 * 506 * @param n Expected dimension. 507 * @throws DimensionMismatchException if the dimensions do not match. 508 */ 509 protected void checkVectorDimensions(int n) 510 throws DimensionMismatchException { 511 if (getDimension() != n) { 512 throw new DimensionMismatchException(getDimension(), n); 513 } 514 } 515 516 /** {@inheritDoc} */ 517 public FieldVector<T> add(FieldVector<T> v) throws DimensionMismatchException { 518 if (v instanceof SparseFieldVector<?>) { 519 return add((SparseFieldVector<T>) v); 520 } else { 521 final int n = v.getDimension(); 522 checkVectorDimensions(n); 523 SparseFieldVector<T> res = new SparseFieldVector<T>(field, 524 getDimension()); 525 for (int i = 0; i < n; i++) { 526 res.setEntry(i, v.getEntry(i).add(getEntry(i))); 527 } 528 return res; 529 } 530 } 531 532 /** 533 * Build an array of elements. 534 * 535 * @param length Size of the array to build. 536 * @return a new array. 537 */ 538 @SuppressWarnings("unchecked") // field is type T 539 private T[] buildArray(final int length) { 540 return (T[]) Array.newInstance(field.getRuntimeClass(), length); 541 } 542 543 544 /** {@inheritDoc} */ 545 @Override 546 public int hashCode() { 547 final int prime = 31; 548 int result = 1; 549 result = prime * result + ((field == null) ? 0 : field.hashCode()); 550 result = prime * result + virtualSize; 551 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 552 while (iter.hasNext()) { 553 iter.advance(); 554 int temp = iter.value().hashCode(); 555 result = prime * result + temp; 556 } 557 return result; 558 } 559 560 561 /** {@inheritDoc} */ 562 @Override 563 public boolean equals(Object obj) { 564 565 if (this == obj) { 566 return true; 567 } 568 569 if (!(obj instanceof SparseFieldVector<?>)) { 570 return false; 571 } 572 573 @SuppressWarnings("unchecked") // OK, because "else if" check below ensures that 574 // other must be the same type as this 575 SparseFieldVector<T> other = (SparseFieldVector<T>) obj; 576 if (field == null) { 577 if (other.field != null) { 578 return false; 579 } 580 } else if (!field.equals(other.field)) { 581 return false; 582 } 583 if (virtualSize != other.virtualSize) { 584 return false; 585 } 586 587 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 588 while (iter.hasNext()) { 589 iter.advance(); 590 T test = other.getEntry(iter.key()); 591 if (!test.equals(iter.value())) { 592 return false; 593 } 594 } 595 iter = other.getEntries().iterator(); 596 while (iter.hasNext()) { 597 iter.advance(); 598 T test = iter.value(); 599 if (!test.equals(getEntry(iter.key()))) { 600 return false; 601 } 602 } 603 return true; 604 } 605 }