/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.math.linear; import java.util.Iterator; import java.util.NoSuchElementException; import org.apache.commons.math.FunctionEvaluationException; import org.apache.commons.math.exception.MathUnsupportedOperationException; import org.apache.commons.math.exception.DimensionMismatchException; import org.apache.commons.math.analysis.BinaryFunction; import org.apache.commons.math.analysis.ComposableFunction; import org.apache.commons.math.analysis.UnivariateRealFunction; import org.apache.commons.math.exception.util.LocalizedFormats; import org.apache.commons.math.util.FastMath; /** * This class provides default basic implementations for many methods in the * {@link RealVector} interface. * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $ * @since 2.1 */ public abstract class AbstractRealVector implements RealVector { /** * Check if instance and specified vectors have the same dimension. * @param v vector to compare instance with * @exception DimensionMismatchException if the vectors do not * have the same dimension */ protected void checkVectorDimensions(RealVector v) { checkVectorDimensions(v.getDimension()); } /** * Check if instance dimension is equal to some expected value. * * @param n expected dimension. * @exception DimensionMismatchException if the dimension is * inconsistent with vector size */ protected void checkVectorDimensions(int n) throws DimensionMismatchException { int d = getDimension(); if (d != n) { throw new DimensionMismatchException(d, n); } } /** * Check if an index is valid. * @param index index to check * @exception MatrixIndexException if index is not valid */ protected void checkIndex(final int index) throws MatrixIndexException { if (index < 0 || index >= getDimension()) { throw new MatrixIndexException(LocalizedFormats.INDEX_OUT_OF_RANGE, index, 0, getDimension() - 1); } } /** {@inheritDoc} */ public void setSubVector(int index, RealVector v) throws MatrixIndexException { checkIndex(index); checkIndex(index + v.getDimension() - 1); setSubVector(index, v.getData()); } /** {@inheritDoc} */ public void setSubVector(int index, double[] v) throws MatrixIndexException { checkIndex(index); checkIndex(index + v.length - 1); for (int i = 0; i < v.length; i++) { setEntry(i + index, v[i]); } } /** {@inheritDoc} */ public RealVector add(double[] v) throws IllegalArgumentException { double[] result = v.clone(); Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { result[e.getIndex()] += e.getValue(); } return new ArrayRealVector(result, false); } /** {@inheritDoc} */ public RealVector add(RealVector v) throws IllegalArgumentException { if (v instanceof ArrayRealVector) { double[] values = ((ArrayRealVector)v).getDataRef(); return add(values); } RealVector result = v.copy(); Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { final int index = e.getIndex(); result.setEntry(index, e.getValue() + result.getEntry(index)); } return result; } /** {@inheritDoc} */ public RealVector subtract(double[] v) throws IllegalArgumentException { double[] result = v.clone(); Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { final int index = e.getIndex(); result[index] = e.getValue() - result[index]; } return new ArrayRealVector(result, false); } /** {@inheritDoc} */ public RealVector subtract(RealVector v) throws IllegalArgumentException { if (v instanceof ArrayRealVector) { double[] values = ((ArrayRealVector)v).getDataRef(); return add(values); } RealVector result = v.copy(); Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { final int index = e.getIndex(); v.setEntry(index, e.getValue() - result.getEntry(index)); } return result; } /** {@inheritDoc} */ public RealVector mapAdd(double d) { return copy().mapAddToSelf(d); } /** {@inheritDoc} */ public RealVector mapAddToSelf(double d) { if (d != 0) { try { return mapToSelf(BinaryFunction.ADD.fix1stArgument(d)); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } return this; } /** {@inheritDoc} */ public abstract AbstractRealVector copy(); /** {@inheritDoc} */ public double dotProduct(double[] v) throws IllegalArgumentException { return dotProduct(new ArrayRealVector(v, false)); } /** {@inheritDoc} */ public double dotProduct(RealVector v) throws IllegalArgumentException { checkVectorDimensions(v); double d = 0; Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { d += e.getValue() * v.getEntry(e.getIndex()); } return d; } /** {@inheritDoc} */ public RealVector ebeDivide(double[] v) throws IllegalArgumentException { return ebeDivide(new ArrayRealVector(v, false)); } /** {@inheritDoc} */ public RealVector ebeMultiply(double[] v) throws IllegalArgumentException { return ebeMultiply(new ArrayRealVector(v, false)); } /** {@inheritDoc} */ public double getDistance(RealVector v) throws IllegalArgumentException { checkVectorDimensions(v); double d = 0; Iterator<Entry> it = iterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { final double diff = e.getValue() - v.getEntry(e.getIndex()); d += diff * diff; } return FastMath.sqrt(d); } /** {@inheritDoc} */ public double getNorm() { double sum = 0; Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { final double value = e.getValue(); sum += value * value; } return FastMath.sqrt(sum); } /** {@inheritDoc} */ public double getL1Norm() { double norm = 0; Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { norm += FastMath.abs(e.getValue()); } return norm; } /** {@inheritDoc} */ public double getLInfNorm() { double norm = 0; Iterator<Entry> it = sparseIterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { norm = FastMath.max(norm, FastMath.abs(e.getValue())); } return norm; } /** {@inheritDoc} */ public double getDistance(double[] v) throws IllegalArgumentException { return getDistance(new ArrayRealVector(v,false)); } /** {@inheritDoc} */ public double getL1Distance(RealVector v) throws IllegalArgumentException { checkVectorDimensions(v); double d = 0; Iterator<Entry> it = iterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { d += FastMath.abs(e.getValue() - v.getEntry(e.getIndex())); } return d; } /** {@inheritDoc} */ public double getL1Distance(double[] v) throws IllegalArgumentException { checkVectorDimensions(v.length); double d = 0; Iterator<Entry> it = iterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { d += FastMath.abs(e.getValue() - v[e.getIndex()]); } return d; } /** {@inheritDoc} */ public double getLInfDistance(RealVector v) throws IllegalArgumentException { checkVectorDimensions(v); double d = 0; Iterator<Entry> it = iterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { d = FastMath.max(FastMath.abs(e.getValue() - v.getEntry(e.getIndex())), d); } return d; } /** {@inheritDoc} */ public double getLInfDistance(double[] v) throws IllegalArgumentException { checkVectorDimensions(v.length); double d = 0; Iterator<Entry> it = iterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { d = FastMath.max(FastMath.abs(e.getValue() - v[e.getIndex()]), d); } return d; } /** Get the index of the minimum entry. * @return index of the minimum entry or -1 if vector length is 0 * or all entries are NaN */ public int getMinIndex() { int minIndex = -1; double minValue = Double.POSITIVE_INFINITY; Iterator<Entry> iterator = iterator(); while (iterator.hasNext()) { final Entry entry = iterator.next(); if (entry.getValue() <= minValue) { minIndex = entry.getIndex(); minValue = entry.getValue(); } } return minIndex; } /** Get the value of the minimum entry. * @return value of the minimum entry or NaN if all entries are NaN */ public double getMinValue() { final int minIndex = getMinIndex(); return minIndex < 0 ? Double.NaN : getEntry(minIndex); } /** Get the index of the maximum entry. * @return index of the maximum entry or -1 if vector length is 0 * or all entries are NaN */ public int getMaxIndex() { int maxIndex = -1; double maxValue = Double.NEGATIVE_INFINITY; Iterator<Entry> iterator = iterator(); while (iterator.hasNext()) { final Entry entry = iterator.next(); if (entry.getValue() >= maxValue) { maxIndex = entry.getIndex(); maxValue = entry.getValue(); } } return maxIndex; } /** Get the value of the maximum entry. * @return value of the maximum entry or NaN if all entries are NaN */ public double getMaxValue() { final int maxIndex = getMaxIndex(); return maxIndex < 0 ? Double.NaN : getEntry(maxIndex); } /** {@inheritDoc} */ public RealVector mapAbs() { return copy().mapAbsToSelf(); } /** {@inheritDoc} */ public RealVector mapAbsToSelf() { try { return mapToSelf(ComposableFunction.ABS); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapAcos() { return copy().mapAcosToSelf(); } /** {@inheritDoc} */ public RealVector mapAcosToSelf() { try { return mapToSelf(ComposableFunction.ACOS); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapAsin() { return copy().mapAsinToSelf(); } /** {@inheritDoc} */ public RealVector mapAsinToSelf() { try { return mapToSelf(ComposableFunction.ASIN); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapAtan() { return copy().mapAtanToSelf(); } /** {@inheritDoc} */ public RealVector mapAtanToSelf() { try { return mapToSelf(ComposableFunction.ATAN); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapCbrt() { return copy().mapCbrtToSelf(); } /** {@inheritDoc} */ public RealVector mapCbrtToSelf() { try { return mapToSelf(ComposableFunction.CBRT); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapCeil() { return copy().mapCeilToSelf(); } /** {@inheritDoc} */ public RealVector mapCeilToSelf() { try { return mapToSelf(ComposableFunction.CEIL); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapCos() { return copy().mapCosToSelf(); } /** {@inheritDoc} */ public RealVector mapCosToSelf() { try { return mapToSelf(ComposableFunction.COS); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapCosh() { return copy().mapCoshToSelf(); } /** {@inheritDoc} */ public RealVector mapCoshToSelf() { try { return mapToSelf(ComposableFunction.COSH); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapDivide(double d) { return copy().mapDivideToSelf(d); } /** {@inheritDoc} */ public RealVector mapDivideToSelf(double d){ try { return mapToSelf(BinaryFunction.DIVIDE.fix2ndArgument(d)); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapExp() { return copy().mapExpToSelf(); } /** {@inheritDoc} */ public RealVector mapExpToSelf() { try { return mapToSelf(ComposableFunction.EXP); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapExpm1() { return copy().mapExpm1ToSelf(); } /** {@inheritDoc} */ public RealVector mapExpm1ToSelf() { try { return mapToSelf(ComposableFunction.EXPM1); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapFloor() { return copy().mapFloorToSelf(); } /** {@inheritDoc} */ public RealVector mapFloorToSelf() { try { return mapToSelf(ComposableFunction.FLOOR); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapInv() { return copy().mapInvToSelf(); } /** {@inheritDoc} */ public RealVector mapInvToSelf() { try { return mapToSelf(ComposableFunction.INVERT); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapLog() { return copy().mapLogToSelf(); } /** {@inheritDoc} */ public RealVector mapLogToSelf() { try { return mapToSelf(ComposableFunction.LOG); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapLog10() { return copy().mapLog10ToSelf(); } /** {@inheritDoc} */ public RealVector mapLog10ToSelf() { try { return mapToSelf(ComposableFunction.LOG10); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapLog1p() { return copy().mapLog1pToSelf(); } /** {@inheritDoc} */ public RealVector mapLog1pToSelf() { try { return mapToSelf(ComposableFunction.LOG1P); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapMultiply(double d) { return copy().mapMultiplyToSelf(d); } /** {@inheritDoc} */ public RealVector mapMultiplyToSelf(double d){ try { return mapToSelf(BinaryFunction.MULTIPLY.fix1stArgument(d)); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapPow(double d) { return copy().mapPowToSelf(d); } /** {@inheritDoc} */ public RealVector mapPowToSelf(double d){ try { return mapToSelf(BinaryFunction.POW.fix2ndArgument(d)); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapRint() { return copy().mapRintToSelf(); } /** {@inheritDoc} */ public RealVector mapRintToSelf() { try { return mapToSelf(ComposableFunction.RINT); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapSignum() { return copy().mapSignumToSelf(); } /** {@inheritDoc} */ public RealVector mapSignumToSelf() { try { return mapToSelf(ComposableFunction.SIGNUM); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapSin() { return copy().mapSinToSelf(); } /** {@inheritDoc} */ public RealVector mapSinToSelf() { try { return mapToSelf(ComposableFunction.SIN); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapSinh() { return copy().mapSinhToSelf(); } /** {@inheritDoc} */ public RealVector mapSinhToSelf() { try { return mapToSelf(ComposableFunction.SINH); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapSqrt() { return copy().mapSqrtToSelf(); } /** {@inheritDoc} */ public RealVector mapSqrtToSelf() { try { return mapToSelf(ComposableFunction.SQRT); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapSubtract(double d) { return copy().mapSubtractToSelf(d); } /** {@inheritDoc} */ public RealVector mapSubtractToSelf(double d){ return mapAddToSelf(-d); } /** {@inheritDoc} */ public RealVector mapTan() { return copy().mapTanToSelf(); } /** {@inheritDoc} */ public RealVector mapTanToSelf() { try { return mapToSelf(ComposableFunction.TAN); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapTanh() { return copy().mapTanhToSelf(); } /** {@inheritDoc} */ public RealVector mapTanhToSelf() { try { return mapToSelf(ComposableFunction.TANH); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealVector mapUlp() { return copy().mapUlpToSelf(); } /** {@inheritDoc} */ public RealVector mapUlpToSelf() { try { return mapToSelf(ComposableFunction.ULP); } catch (FunctionEvaluationException e) { throw new IllegalArgumentException(e); } } /** {@inheritDoc} */ public RealMatrix outerProduct(RealVector v) throws IllegalArgumentException { RealMatrix product; if (v instanceof SparseRealVector || this instanceof SparseRealVector) { product = new OpenMapRealMatrix(this.getDimension(), v.getDimension()); } else { product = new Array2DRowRealMatrix(this.getDimension(), v.getDimension()); } Iterator<Entry> thisIt = sparseIterator(); Entry thisE = null; while (thisIt.hasNext() && (thisE = thisIt.next()) != null) { Iterator<Entry> otherIt = v.sparseIterator(); Entry otherE = null; while (otherIt.hasNext() && (otherE = otherIt.next()) != null) { product.setEntry(thisE.getIndex(), otherE.getIndex(), thisE.getValue() * otherE.getValue()); } } return product; } /** {@inheritDoc} */ public RealMatrix outerProduct(double[] v) throws IllegalArgumentException { return outerProduct(new ArrayRealVector(v, false)); } /** {@inheritDoc} */ public RealVector projection(double[] v) throws IllegalArgumentException { return projection(new ArrayRealVector(v, false)); } /** {@inheritDoc} */ public void set(double value) { Iterator<Entry> it = iterator(); Entry e = null; while (it.hasNext() && (e = it.next()) != null) { e.setValue(value); } } /** {@inheritDoc} */ public double[] toArray() { int dim = getDimension(); double[] values = new double[dim]; for (int i = 0; i < dim; i++) { values[i] = getEntry(i); } return values; } /** {@inheritDoc} */ public double[] getData() { return toArray(); } /** {@inheritDoc} */ public RealVector unitVector() { RealVector copy = copy(); copy.unitize(); return copy; } /** {@inheritDoc} */ public void unitize() { mapDivideToSelf(getNorm()); } /** {@inheritDoc} */ public Iterator<Entry> sparseIterator() { return new SparseEntryIterator(); } /** {@inheritDoc} */ public Iterator<Entry> iterator() { final int dim = getDimension(); return new Iterator<Entry>() { /** Current index. */ private int i = 0; /** Current entry. */ private EntryImpl e = new EntryImpl(); /** {@inheritDoc} */ public boolean hasNext() { return i < dim; } /** {@inheritDoc} */ public Entry next() { e.setIndex(i++); return e; } /** {@inheritDoc} */ public void remove() { throw new MathUnsupportedOperationException(); } }; } /** {@inheritDoc} */ public RealVector map(UnivariateRealFunction function) throws FunctionEvaluationException { return copy().mapToSelf(function); } /** {@inheritDoc} */ public RealVector mapToSelf(UnivariateRealFunction function) throws FunctionEvaluationException { Iterator<Entry> it = (function.value(0) == 0) ? sparseIterator() : iterator(); Entry e; while (it.hasNext() && (e = it.next()) != null) { e.setValue(function.value(e.getValue())); } return this; } /** An entry in the vector. */ protected class EntryImpl extends Entry { /** Simple constructor. */ public EntryImpl() { setIndex(0); } /** {@inheritDoc} */ @Override public double getValue() { return getEntry(getIndex()); } /** {@inheritDoc} */ @Override public void setValue(double newValue) { setEntry(getIndex(), newValue); } } /** * This class should rare be used, but is here to provide * a default implementation of sparseIterator(), which is implemented * by walking over the entries, skipping those whose values are the default one. * * Concrete subclasses which are SparseVector implementations should * make their own sparse iterator, not use this one. * * This implementation might be useful for ArrayRealVector, when expensive * operations which preserve the default value are to be done on the entries, * and the fraction of non-default values is small (i.e. someone took a * SparseVector, and passed it into the copy-constructor of ArrayRealVector) */ protected class SparseEntryIterator implements Iterator<Entry> { /** Dimension of the vector. */ private final int dim; /** last entry returned by {@link #next()} */ private EntryImpl current; /** Next entry for {@link #next()} to return. */ private EntryImpl next; /** Simple constructor. */ protected SparseEntryIterator() { dim = getDimension(); current = new EntryImpl(); next = new EntryImpl(); if (next.getValue() == 0) { advance(next); } } /** Advance an entry up to the next nonzero one. * @param e entry to advance */ protected void advance(EntryImpl e) { if (e == null) { return; } do { e.setIndex(e.getIndex() + 1); } while (e.getIndex() < dim && e.getValue() == 0); if (e.getIndex() >= dim) { e.setIndex(-1); } } /** {@inheritDoc} */ public boolean hasNext() { return next.getIndex() >= 0; } /** {@inheritDoc} */ public Entry next() { int index = next.getIndex(); if (index < 0) { throw new NoSuchElementException(); } current.setIndex(index); advance(next); return current; } /** {@inheritDoc} */ public void remove() { throw new MathUnsupportedOperationException(); } } }