blob: e39c9ceefa91582c116383ffdd478265874f5918 [file] [log] [blame]
/*
* 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();
}
}
}