DoubleVector.java

package org.opentrafficsim.core.value.vdouble.vector;

import java.io.Serializable;

import org.opentrafficsim.core.unit.SICoefficients;
import org.opentrafficsim.core.unit.SIUnit;
import org.opentrafficsim.core.unit.Unit;
import org.opentrafficsim.core.value.Absolute;
import org.opentrafficsim.core.value.AbstractValue;
import org.opentrafficsim.core.value.DenseData;
import org.opentrafficsim.core.value.Format;
import org.opentrafficsim.core.value.Relative;
import org.opentrafficsim.core.value.SparseData;
import org.opentrafficsim.core.value.ValueException;
import org.opentrafficsim.core.value.ValueUtil;
import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;

import cern.colt.matrix.tdouble.DoubleMatrix1D;
import cern.colt.matrix.tdouble.impl.DenseDoubleMatrix1D;
import cern.colt.matrix.tdouble.impl.SparseDoubleMatrix1D;

/**
 * Immutable DoubleVector.
 * <p>
 * This file was generated by the OpenTrafficSim value classes generator, 09 mrt, 2015
 * <p>
 * Copyright (c) 2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
 * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
 * <p>
 * @version 09 mrt, 2015 <br>
 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
 * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
 * @param <U> Unit; the unit of this DoubleVector
 */
public abstract class DoubleVector<U extends Unit<U>> extends AbstractValue<U> implements
        Serializable,
    ReadOnlyDoubleVectorFunctions<U>
{
    /**  */
    private static final long serialVersionUID = 20150309L;

    /** 
     * The internal storage for the vector; internally the values are stored in standard SI unit; storage can be dense
     * or sparse.
     */
    private DoubleMatrix1D vectorSI;

    /**
     * Construct a new Immutable DoubleVector.
     * @param unit U; the unit of the new DoubleVector
     */
    protected  DoubleVector(final U unit)
    {
        super(unit);
        // System.out.println("Created DoubleVector");
    }

    /**
     * @param <U> Unit
     */
    public abstract static class Abs<U extends Unit<U>> extends DoubleVector<U> implements Absolute
    {
        /**  */
        private static final long serialVersionUID = 20150309L;

        /**
         * Construct a new Absolute Immutable DoubleVector.
         * @param unit U; the unit of the new Absolute Immutable DoubleVector
         */
        protected Abs(final U unit)
        {
            super(unit);
            // System.out.println("Created Abs");
        }

        /**
         * @param <U> Unit
         */
        public static class Dense<U extends Unit<U>> extends Abs<U> implements DenseData
        {
            /**  */
            private static final long serialVersionUID = 20150309L;

            /**
             * Construct a new Absolute Dense Immutable DoubleVector.
             * @param values double[]; the values of the entries in the new Absolute Dense Immutable DoubleVector
             * @param unit U; the unit of the new Absolute Dense Immutable DoubleVector
             * @throws ValueException when values is null
             */
            public Dense(final double[] values, final U unit) throws ValueException
            {
                super(unit);
                // System.out.println("Created Dense");
                initialize(values);
            }

            /**
             * Construct a new Absolute Dense Immutable DoubleVector.
             * @param values DoubleScalar.Abs&lt;U&gt;[]; the values of the entries in the new Absolute Dense Immutable
             *            DoubleVector
             * @throws ValueException when values has zero entries
             */
            public Dense(final DoubleScalar.Abs<U>[] values) throws ValueException
            {
                super(checkNonEmpty(values)[0].getUnit());
                // System.out.println("Created Dense");
                initialize(values);
            }

            /**
             * For package internal use only.
             * @param values DoubleMatrix1D; the values of the entries in the new Absolute Dense Immutable DoubleVector
             * @param unit U; the unit of the new Absolute Dense Immutable DoubleVector
             */
            protected Dense(final DoubleMatrix1D values, final U unit)
            {
                super(unit);
                // System.out.println("Created Dense");
                initialize(values); // shallow copy
            }

            /** {@inheritDoc} */
            @Override
            public final MutableDoubleVector.Abs.Dense<U> mutable()
            {
                return new MutableDoubleVector.Abs.Dense<U>(getVectorSI(), getUnit());
            }

            /** {@inheritDoc} */
            @Override
            protected final DoubleMatrix1D createMatrix1D(final int size)
            {
                return new DenseDoubleMatrix1D(size);
            }

            /** {@inheritDoc} */
            @Override
            public final DoubleVector.Abs.Dense<U> copy()
            {
                return this; // That was easy...
            }

        }

        /**
         * @param <U> Unit
         */
        public static class Sparse<U extends Unit<U>> extends Abs<U> implements SparseData
        {
            /**  */
            private static final long serialVersionUID = 20150309L;

            /**
             * Construct a new Absolute Sparse Immutable DoubleVector.
             * @param values double[]; the values of the entries in the new Absolute Sparse Immutable DoubleVector
             * @param unit U; the unit of the new Absolute Sparse Immutable DoubleVector
             * @throws ValueException when values is null
             */
            public Sparse(final double[] values, final U unit) throws ValueException
            {
                super(unit);
                // System.out.println("Created Sparse");
                initialize(values);
            }

            /**
             * Construct a new Absolute Sparse Immutable DoubleVector.
             * @param values DoubleScalar.Abs&lt;U&gt;[]; the values of the entries in the new Absolute Sparse Immutable
             *            DoubleVector
             * @throws ValueException when values has zero entries
             */
            public Sparse(final DoubleScalar.Abs<U>[] values) throws ValueException
            {
                super(checkNonEmpty(values)[0].getUnit());
                // System.out.println("Created Sparse");
                initialize(values);
            }

            /**
             * For package internal use only.
             * @param values DoubleMatrix1D; the values of the entries in the new Absolute Sparse Immutable DoubleVector
             * @param unit U; the unit of the new Absolute Sparse Immutable DoubleVector
             */
            protected Sparse(final DoubleMatrix1D values, final U unit)
            {
                super(unit);
                // System.out.println("Created Sparse");
                initialize(values); // shallow copy
            }

            /** {@inheritDoc} */
            @Override
            public final MutableDoubleVector.Abs.Sparse<U> mutable()
            {
                return new MutableDoubleVector.Abs.Sparse<U>(getVectorSI(), getUnit());
            }

            /** {@inheritDoc} */
            @Override
            protected final DoubleMatrix1D createMatrix1D(final int size)
            {
                return new SparseDoubleMatrix1D(size);
            }

            /** {@inheritDoc} */
            @Override
            public final DoubleVector.Abs.Sparse<U> copy()
            {
                return this; // That was easy...
            }

        }

        /** {@inheritDoc} */
        @Override
        public final DoubleScalar.Abs<U> get(final int index) throws ValueException
        {
            return new DoubleScalar.Abs<U>(getInUnit(index, getUnit()), getUnit());
        }

    }

    /**
     * @param <U> Unit
     */
    public abstract static class Rel<U extends Unit<U>> extends DoubleVector<U> implements Relative
    {
        /**  */
        private static final long serialVersionUID = 20150309L;

        /**
         * Construct a new Relative Immutable DoubleVector.
         * @param unit U; the unit of the new Relative Immutable DoubleVector
         */
        protected Rel(final U unit)
        {
            super(unit);
            // System.out.println("Created Rel");
        }

        /**
         * @param <U> Unit
         */
        public static class Dense<U extends Unit<U>> extends Rel<U> implements DenseData
        {
            /**  */
            private static final long serialVersionUID = 20150309L;

            /**
             * Construct a new Relative Dense Immutable DoubleVector.
             * @param values double[]; the values of the entries in the new Relative Dense Immutable DoubleVector
             * @param unit U; the unit of the new Relative Dense Immutable DoubleVector
             * @throws ValueException when values is null
             */
            public Dense(final double[] values, final U unit) throws ValueException
            {
                super(unit);
                // System.out.println("Created Dense");
                initialize(values);
            }

            /**
             * Construct a new Relative Dense Immutable DoubleVector.
             * @param values DoubleScalar.Rel&lt;U&gt;[]; the values of the entries in the new Relative Dense Immutable
             *            DoubleVector
             * @throws ValueException when values has zero entries
             */
            public Dense(final DoubleScalar.Rel<U>[] values) throws ValueException
            {
                super(checkNonEmpty(values)[0].getUnit());
                // System.out.println("Created Dense");
                initialize(values);
            }

            /**
             * For package internal use only.
             * @param values DoubleMatrix1D; the values of the entries in the new Relative Dense Immutable DoubleVector
             * @param unit U; the unit of the new Relative Dense Immutable DoubleVector
             */
            protected Dense(final DoubleMatrix1D values, final U unit)
            {
                super(unit);
                // System.out.println("Created Dense");
                initialize(values); // shallow copy
            }

            /** {@inheritDoc} */
            @Override
            public final MutableDoubleVector.Rel.Dense<U> mutable()
            {
                return new MutableDoubleVector.Rel.Dense<U>(getVectorSI(), getUnit());
            }

            /** {@inheritDoc} */
            @Override
            protected final DoubleMatrix1D createMatrix1D(final int size)
            {
                return new DenseDoubleMatrix1D(size);
            }

            /** {@inheritDoc} */
            @Override
            public final DoubleVector.Rel.Dense<U> copy()
            {
                return this; // That was easy...
            }

        }

        /**
         * @param <U> Unit
         */
        public static class Sparse<U extends Unit<U>> extends Rel<U> implements SparseData
        {
            /**  */
            private static final long serialVersionUID = 20150309L;

            /**
             * Construct a new Relative Sparse Immutable DoubleVector.
             * @param values double[]; the values of the entries in the new Relative Sparse Immutable DoubleVector
             * @param unit U; the unit of the new Relative Sparse Immutable DoubleVector
             * @throws ValueException when values is null
             */
            public Sparse(final double[] values, final U unit) throws ValueException
            {
                super(unit);
                // System.out.println("Created Sparse");
                initialize(values);
            }

            /**
             * Construct a new Relative Sparse Immutable DoubleVector.
             * @param values DoubleScalar.Rel&lt;U&gt;[]; the values of the entries in the new Relative Sparse Immutable
             *            DoubleVector
             * @throws ValueException when values has zero entries
             */
            public Sparse(final DoubleScalar.Rel<U>[] values) throws ValueException
            {
                super(checkNonEmpty(values)[0].getUnit());
                // System.out.println("Created Sparse");
                initialize(values);
            }

            /**
             * For package internal use only.
             * @param values DoubleMatrix1D; the values of the entries in the new Relative Sparse Immutable DoubleVector
             * @param unit U; the unit of the new Relative Sparse Immutable DoubleVector
             */
            protected Sparse(final DoubleMatrix1D values, final U unit)
            {
                super(unit);
                // System.out.println("Created Sparse");
                initialize(values); // shallow copy
            }

            /** {@inheritDoc} */
            @Override
            public final MutableDoubleVector.Rel.Sparse<U> mutable()
            {
                return new MutableDoubleVector.Rel.Sparse<U>(getVectorSI(), getUnit());
            }

            /** {@inheritDoc} */
            @Override
            protected final DoubleMatrix1D createMatrix1D(final int size)
            {
                return new SparseDoubleMatrix1D(size);
            }

            /** {@inheritDoc} */
            @Override
            public final DoubleVector.Rel.Sparse<U> copy()
            {
                return this; // That was easy...
            }

        }

        /** {@inheritDoc} */
        @Override
        public final DoubleScalar.Rel<U> get(final int index) throws ValueException
        {
            return new DoubleScalar.Rel<U>(getInUnit(index, getUnit()), getUnit());
        }

    }

    /**
     * Retrieve the internal data.
     * @return DoubleMatrix1D; the data in the internal format
     */
    protected final DoubleMatrix1D getVectorSI()
    {
        return this.vectorSI;
    }

    /**
     * Make a deep copy of the data (used ONLY in the MutableDoubleVector sub class).
     */
    protected final void deepCopyData()
    {
        this.vectorSI = getVectorSI().copy(); // makes a deep copy, using multithreading
    }

    /**
     * Create a mutable version of this DoubleVector. <br>
     * The mutable version is created with a shallow copy of the data and the internal copyOnWrite flag set. The first
     * operation in the mutable version that modifies the data shall trigger a deep copy of the data.
     * @return MutableDoubleVector&lt;U&gt;; mutable version of this DoubleVector
     */
    public abstract MutableDoubleVector<U> mutable();

    /**
     * Import the values and convert them into the SI standard unit.
     * @param values double[]; an array of values
     * @throws ValueException when values is null
     */
    protected final void initialize(final double[] values) throws ValueException
    {
        if (null == values)
        {
            throw new ValueException("values is null");
        }
        this.vectorSI = createMatrix1D(values.length);
        if (getUnit().equals(getUnit().getStandardUnit()))
        {
            this.vectorSI.assign(values);
        }
        else
        {
            for (int index = values.length; --index >= 0;)
            {
                safeSet(index, expressAsSIUnit(values[index]));
            }
        }
    }

    /**
     * Import the values from an existing DoubleMatrix1D. This makes a shallow copy.
     * @param values DoubleMatrix1D; the values
     */
    protected final void initialize(final DoubleMatrix1D values)
    {
        this.vectorSI = values;
    }

    /**
     * Construct the vector and store the values in the standard SI unit.
     * @param values DoubleScalar&lt;U&gt;[]; an array of values
     * @throws ValueException when values is null, or empty
     */
    protected final void initialize(final DoubleScalar<U>[] values) throws ValueException
    {
        if (null == values)
        {
            throw new ValueException("values is null");
        }
        this.vectorSI = createMatrix1D(values.length);
        for (int index = 0; index < values.length; index++)
        {
            safeSet(index, values[index].getSI());
            }
    }

    /**
     * Create storage for the data. <br/>
     * This method must be implemented by each leaf class.
     * @param size int; the number of cells in the vector
     * @return DoubleMatrix1D; an instance of the right type of DoubleMatrix1D (absolute/relative, dense/sparse, etc.)
     */
    protected abstract DoubleMatrix1D createMatrix1D(final int size);

    /**
     * Create a double[] array filled with the values in the standard SI unit.
     * @return double[]; array of values in the standard SI unit
     */
    public final double[] getValuesSI()
    {
        return this.vectorSI.toArray(); // this makes a deep copy
    }

    /**
     * Create a double[] array filled with the values in the original unit.
     * @return double[]; the values in the original unit
     */
    public final double[] getValuesInUnit()
    {
        return getValuesInUnit(getUnit());
    }

    /**
     * Create a double[] array filled with the values converted into a specified unit.
     * @param targetUnit U; the unit into which the values are converted for use
     * @return double[]; the values converted into the specified unit
     */
    public final double[] getValuesInUnit(final U targetUnit)
    {
        double[] values = this.vectorSI.toArray();
        for (int i = values.length; --i >= 0;)
        {
            values[i] = ValueUtil.expressAsUnit(values[i], targetUnit);
        }
        return values;
    }

    /** {@inheritDoc} */
    @Override
    public final int size()
    {
        return (int) this.vectorSI.size();
    }

    /** {@inheritDoc} */
    @Override
    public final double getSI(final int index) throws ValueException
    {
        checkIndex(index);
        return safeGet(index);
    }

    /** {@inheritDoc} */
    @Override
    public final double getInUnit(final int index) throws ValueException
    {
        return expressAsSpecifiedUnit(getSI(index));
    }

    /** {@inheritDoc} */
    @Override
    public final double getInUnit(final int index, final U targetUnit) throws ValueException
    {
        return ValueUtil.expressAsUnit(getSI(index), targetUnit);
    }

    /** {@inheritDoc} */
    @Override
    public final double zSum()
    {
        return this.vectorSI.zSum();
    }

    /** {@inheritDoc} */
    @Override
    public final int cardinality()
    {
        return this.vectorSI.cardinality();
    }

    /** {@inheritDoc} */
    @Override
    public final String toString()
    {
        return toString(getUnit(), false, true);
    }

    /**
     * Print this DoubleVector with the values expressed in the specified unit.
     * @param displayUnit U; the unit into which the values are converted for display
     * @return String; printable string with the vector contents expressed in the specified unit
     */
    public final String toString(final U displayUnit)
    {
        return toString(displayUnit, false, true);
    }

    /**
     * Print this DoubleVector with optional type and unit information.
     * @param verbose boolean; if true; include type info; if false; exclude type info
     * @param withUnit boolean; if true; include the unit; of false; exclude the unit
     * @return String; printable string with the vector contents
     */
    public final String toString(final boolean verbose, final boolean withUnit)
    {
        return toString(getUnit(), verbose, withUnit);
    }

    /**
     * Print this DoubleVector with the values expressed in the specified unit.
     * @param displayUnit U; the unit into which the values are converted for display
     * @param verbose boolean; if true; include type info; if false; exclude type info
     * @param withUnit boolean; if true; include the unit; of false; exclude the unit
     * @return String; printable string with the vector contents
     */
    public final String toString(final U displayUnit, final boolean verbose, final boolean withUnit)
    {
        StringBuffer buf = new StringBuffer();
        if (verbose)
        {
            if (this instanceof MutableDoubleVector)
            {
                buf.append("Mutable   ");
                if (this instanceof MutableDoubleVector.Abs.Dense)
                {
                    buf.append("Abs Dense  ");
                }
                else if (this instanceof MutableDoubleVector.Rel.Dense)
                {
                    buf.append("Rel Dense  ");
                }
                else if (this instanceof MutableDoubleVector.Abs.Sparse)
                {
                    buf.append("Abs Sparse ");
                }
                else if (this instanceof MutableDoubleVector.Rel.Sparse)
                {
                    buf.append("Rel Sparse ");
                }
                else
                {
                    buf.append("??? ");
                }
            }
            else
            {
                buf.append("Immutable ");
                if (this instanceof DoubleVector.Abs.Dense)
                {
                    buf.append("Abs Dense  ");
                }
                else if (this instanceof DoubleVector.Rel.Dense)
                {
                    buf.append("Rel Dense  ");
                }
                else if (this instanceof DoubleVector.Abs.Sparse)
                {
                    buf.append("Abs Sparse ");
                }
                else if (this instanceof DoubleVector.Rel.Sparse)
                {
                    buf.append("Rel Sparse ");
                }
                else
                {
                    buf.append("??? ");
                }
            }
        }
        for (int i = 0; i < size(); i++)
        {
            double d = ValueUtil.expressAsUnit(safeGet(i), displayUnit);
            buf.append(" " + Format.format(d));
        }
        if (withUnit)
        {
            buf.append(displayUnit.getAbbreviation());
        }
        return buf.toString();
    }

    /**
     * Centralized size equality check.
     * @param other DoubleVector&lt;?&gt;; other DoubleVector
     * @throws ValueException when other is null, or vectors have unequal size
     */
    protected final void checkSize(final DoubleVector<?> other) throws ValueException
    {
        if (null == other)
        {
            throw new ValueException("other is null");
        }
        if (size() != other.size())
        {
            throw new ValueException("The vectors have different sizes: " + size() + " != " + other.size());
        }
    }

    /**
     * Centralized size equality check.
     * @param other double[]; array of double
     * @throws ValueException when vectors have unequal size
     */
    protected final void checkSize(final double[] other) throws ValueException
    {
        if (size() != other.length)
        {
        throw new ValueException("The vector and the array have different sizes: " + size() + " != " + other.length);
        }
    }

    /**
     * Check that a provided index is valid.
     * @param index int; the value to check
     * @throws ValueException when index is invalid
     */
    protected final void checkIndex(final int index) throws ValueException
    {
        if (index < 0 || index >= size())
        {
            throw new ValueException("index out of range (valid range is 0.." + (size() - 1) + ", got " + index + ")");
        }
    }

    /**
     * Retrieve a value in vectorSI without checking validity of the index.
     * @param index int; the index
     * @return double; the value stored at that index
     */
    protected final double safeGet(final int index)
    {
        return this.vectorSI.getQuick(index);
    }

    /**
     * Modify a value in vectorSI without checking validity of the index.
     * @param index int; the index
     * @param valueSI double; the new value for the entry in vectorSI
     */
    protected final void safeSet(final int index, final double valueSI)
    {
        this.vectorSI.setQuick(index, valueSI);
    }

    /**
     * Create a deep copy of the data.
     * @return DoubleMatrix1D; deep copy of the data
     */
    protected final DoubleMatrix1D deepCopyOfData()
    {
        return this.vectorSI.copy();
    }

    /**
     * Check that a provided array can be used to create some descendant of a DoubleVector.
     * @param dsArray DoubleScalar&lt;U&gt;[]; the provided array
     * @param <U> Unit; the unit of the DoubleScalar array
     * @return DoubleScalar&lt;U&gt;[]; the provided array
     * @throws ValueException when the array has length equal to 0
     */
    protected static <U extends Unit<U>> DoubleScalar<U>[] checkNonEmpty(final DoubleScalar<U>[] dsArray)
            throws ValueException
    {
        if (0 == dsArray.length)
        {
            throw new ValueException(
                    "Cannot create a DoubleVector or MutableDoubleVector from an empty array of DoubleScalar");
        }
        return dsArray;
    }

    /** {@inheritDoc} */
    @Override
    public final int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + this.vectorSI.hashCode();
        return result;
    }

    /** {@inheritDoc} */
    @Override
    public final boolean equals(final Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj == null)
        {
        return false;
        }
        if (!(obj instanceof DoubleVector))
        {
            return false;
        }
        DoubleVector<?> other = (DoubleVector<?>) obj;
        // unequal if not both Absolute or both Relative
        if (this.isAbsolute() != other.isAbsolute() || this.isRelative() != other.isRelative())
        {
            return false;
        }
        // unequal if the standard SI units differ
        if (!this.getUnit().getStandardUnit().equals(other.getUnit().getStandardUnit()))
        {
            return false;
        }
        // Colt's equals also tests the size of the vector
        if (!getVectorSI().equals(other.getVectorSI()))
        {
            return false;
        }
        return true;
    }

    /**********************************************************************************/
    /********************************* STATIC METHODS *********************************/
    /**********************************************************************************/

    /**
     * Add two DoubleVectors value by value and store the result in a new MutableDoubleVector.Abs.Dense&lt;U&gt;.
     * @param left DoubleVector.Abs.Dense&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Dense<U> plus(final DoubleVector.Abs.Dense<U> left,
            final DoubleVector.Rel<U> right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Dense<U>) left.mutable().incrementBy(right);
    }

    /**
     * Add two DoubleVectors value by value and store the result in a new MutableDoubleVector.Abs.Dense&lt;U&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Dense&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Dense<U> plus(final DoubleVector.Abs.Sparse<U> left,
            final DoubleVector.Rel.Dense<U> right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Dense<U>) sparseToDense(left).incrementBy(right);
    }

    /**
     * Add two DoubleVectors value by value and store the result in a new MutableDoubleVector.Abs.Sparse&lt;U&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Sparse&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Sparse&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Sparse<U> plus(final DoubleVector.Abs.Sparse<U> left,
            final DoubleVector.Rel.Sparse<U> right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Sparse<U>) left.mutable().incrementBy(right);
    }

    /**
     * Add two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Dense&lt;U&gt;.
     * @param left DoubleVector.Rel.Dense&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> plus(final DoubleVector.Rel.Dense<U> left,
            final DoubleVector.Rel<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Dense<U>) left.mutable().incrementBy(right);
    }

    /**
     * Add two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Dense&lt;U&gt;.
     * @param left DoubleVector.Rel.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Dense&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> plus(final DoubleVector.Rel.Sparse<U> left,
            final DoubleVector.Rel.Dense<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Dense<U>) sparseToDense(left).incrementBy(right);
    }

    /**
     * Add two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Sparse&lt;U&gt;.
     * @param left DoubleVector.Rel.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Sparse&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Sparse&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Sparse<U> plus(final DoubleVector.Rel.Sparse<U> left,
            final DoubleVector.Rel.Sparse<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Sparse<U>) left.mutable().incrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Dense&lt;U&gt;.
     * @param left DoubleVector.Abs.Dense&lt;U&gt;; the left operand
     * @param right DoubleVector.Abs&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> minus(final DoubleVector.Abs.Dense<U> left,
            final DoubleVector.Abs<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Dense<U>) new MutableDoubleVector.Rel.Dense<U>(left.deepCopyOfData(),
                    left.getUnit()).decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Sparse&lt;U&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Abs.Sparse&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Sparse&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Sparse<U> minus(final DoubleVector.Abs.Sparse<U> left,
            final DoubleVector.Abs.Sparse<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Sparse<U>) new MutableDoubleVector.Rel.Sparse<U>(left.deepCopyOfData(),
                    left.getUnit()).decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Dense&lt;U&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Abs.Dense&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> minus(final DoubleVector.Abs.Sparse<U> left,
            final DoubleVector.Abs.Dense<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Dense<U>) new MutableDoubleVector.Rel.Dense<U>(left.deepCopyOfData(),
                    left.getUnit()).decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Abs.Dense&lt;U&gt;.
     * @param left DoubleVector.Abs.Dense&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Dense<U> minus(final DoubleVector.Abs.Dense<U> left,
            final DoubleVector.Rel<U> right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Dense<U>) left.mutable().decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Abs.Dense&lt;U&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Dense&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Dense<U> minus(final DoubleVector.Abs.Sparse<U> left,
            final DoubleVector.Rel.Dense<U> right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Dense<U>) sparseToDense(left).decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Abs.Sparse&lt;U&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Sparse&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Sparse&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Sparse<U> minus(final DoubleVector.Abs.Sparse<U> left,
            final DoubleVector.Rel.Sparse<U> right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Sparse<U>) left.mutable().decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Dense&lt;U&gt;.
     * @param left DoubleVector.Rel.Dense&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> minus(final DoubleVector.Rel.Dense<U> left,
            final DoubleVector.Rel<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Dense<U>) left.mutable().decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Dense&lt;U&gt;.
     * @param left DoubleVector.Rel.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Dense&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> minus(final DoubleVector.Rel.Sparse<U> left,
            final DoubleVector.Rel.Dense<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Dense<U>) sparseToDense(left).decrementBy(right);
    }

    /**
     * Subtract two DoubleVectors value by value and store the result in a new MutableDoubleVector.Rel.Sparse&lt;U&gt;.
     * @param left DoubleVector.Rel.Sparse&lt;U&gt;; the left operand
     * @param right DoubleVector.Rel.Sparse&lt;U&gt;; the right operand
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Sparse&lt;U&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Sparse<U> minus(final DoubleVector.Rel.Sparse<U> left,
            final DoubleVector.Rel.Sparse<U> right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Sparse<U>) left.mutable().decrementBy(right);
    }

    // TODO Decide if you ever need multiply an Absolute with anything
    /**
     * Multiply two DoubleVectors value by value and store the result in a new
     * MutableDoubleVector.Abs.Dense&lt;SIUnit&gt;.
     * @param left DoubleVector.Abs.Dense&lt;?&gt;; the left operand
     * @param right DoubleVector.Abs.Dense&lt;?&gt;; the right operand
     * @return MutableDoubleVector.Abs.Dense&lt;SIUnit&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static MutableDoubleVector.Abs.Dense<SIUnit> times(final DoubleVector.Abs.Dense<?> left,
            final DoubleVector.Abs.Dense<?> right) throws ValueException
    {
        SIUnit targetUnit =
                Unit.lookupOrCreateSIUnitWithSICoefficients(SICoefficients.multiply(left.getUnit().getSICoefficients(),
                        right.getUnit().getSICoefficients()).toString());
        MutableDoubleVector.Abs.Dense<SIUnit> work =
                new MutableDoubleVector.Abs.Dense<SIUnit>(left.deepCopyOfData(), targetUnit);
        work.scaleValueByValue(right);
        return work;
    }

    /**
     * Multiply two DoubleVectors value by value and store the result in a new
     * MutableDoubleVector.Abs.Sparse&lt;SIUnit&gt;.
     * @param left DoubleVector.Abs.Dense&lt;?&gt;; the left operand
     * @param right DoubleVector.Abs.Sparse&lt;?&gt;; the right operand
     * @return MutableDoubleVector.Abs.Sparse&lt;SIUnit&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static MutableDoubleVector.Abs.Sparse<SIUnit> times(final DoubleVector.Abs.Dense<?> left,
            final DoubleVector.Abs.Sparse<?> right) throws ValueException
    {
        SIUnit targetUnit =
                Unit.lookupOrCreateSIUnitWithSICoefficients(SICoefficients.multiply(left.getUnit().getSICoefficients(),
                        right.getUnit().getSICoefficients()).toString());
        MutableDoubleVector.Abs.Sparse<SIUnit> work =
                new MutableDoubleVector.Abs.Sparse<SIUnit>(left.deepCopyOfData(), targetUnit);
        work.scaleValueByValue(right);
        return work;
    }

    /**
     * Multiply two DoubleVectors value by value and store the result in a new
     * MutableDoubleVector.Abs.Sparse&lt;SIUnit&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;?&gt;; the left operand
     * @param right DoubleVector.Abs&lt;?&gt;; the right operand
     * @return MutableDoubleVector.Abs.Sparse&lt;SIUnit&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static MutableDoubleVector.Abs.Sparse<SIUnit> times(final DoubleVector.Abs.Sparse<?> left,
            final DoubleVector.Abs<?> right) throws ValueException
    {
        SIUnit targetUnit =
                Unit.lookupOrCreateSIUnitWithSICoefficients(SICoefficients.multiply(left.getUnit().getSICoefficients(),
                        right.getUnit().getSICoefficients()).toString());
        MutableDoubleVector.Abs.Sparse<SIUnit> work =
                new MutableDoubleVector.Abs.Sparse<SIUnit>(left.deepCopyOfData(), targetUnit);
        work.scaleValueByValue(right);
        return work;
    }

    /**
     * Multiply two DoubleVectors value by value and store the result in a new
     * MutableDoubleVector.Rel.Dense&lt;SIUnit&gt;.
     * @param left DoubleVector.Rel.Dense&lt;?&gt;; the left operand
     * @param right DoubleVector.Rel.Dense&lt;?&gt;; the right operand
     * @return MutableDoubleVector.Rel.Dense&lt;SIUnit&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static MutableDoubleVector.Rel.Dense<SIUnit> times(final DoubleVector.Rel.Dense<?> left,
            final DoubleVector.Rel.Dense<?> right) throws ValueException
    {
        SIUnit targetUnit =
                Unit.lookupOrCreateSIUnitWithSICoefficients(SICoefficients.multiply(left.getUnit().getSICoefficients(),
                        right.getUnit().getSICoefficients()).toString());
        MutableDoubleVector.Rel.Dense<SIUnit> work =
                new MutableDoubleVector.Rel.Dense<SIUnit>(left.deepCopyOfData(), targetUnit);
        work.scaleValueByValue(right);
        return work;
    }

    /**
     * Multiply two DoubleVectors value by value and store the result in a new
     * MutableDoubleVector.Rel.Sparse&lt;SIUnit&gt;.
     * @param left DoubleVector.Rel.Dense&lt;?&gt;; the left operand
     * @param right DoubleVector.Rel.Sparse&lt;?&gt;; the right operand
     * @return MutableDoubleVector.Rel.Sparse&lt;SIUnit&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static MutableDoubleVector.Rel.Sparse<SIUnit> times(final DoubleVector.Rel.Dense<?> left,
            final DoubleVector.Rel.Sparse<?> right) throws ValueException
    {
        SIUnit targetUnit =
                Unit.lookupOrCreateSIUnitWithSICoefficients(SICoefficients.multiply(left.getUnit().getSICoefficients(),
                        right.getUnit().getSICoefficients()).toString());
        MutableDoubleVector.Rel.Sparse<SIUnit> work =
                new MutableDoubleVector.Rel.Sparse<SIUnit>(left.deepCopyOfData(), targetUnit);
        work.scaleValueByValue(right);
        return work;
    }

    /**
     * Multiply two DoubleVectors value by value and store the result in a new
     * MutableDoubleVector.Rel.Sparse&lt;SIUnit&gt;.
     * @param left DoubleVector.Rel.Sparse&lt;?&gt;; the left operand
     * @param right DoubleVector.Rel&lt;?&gt;; the right operand
     * @return MutableDoubleVector.Rel.Sparse&lt;SIUnit&gt;
     * @throws ValueException when the vectors do not have the same size
     */
    public static MutableDoubleVector.Rel.Sparse<SIUnit> times(final DoubleVector.Rel.Sparse<?> left,
            final DoubleVector.Rel<?> right) throws ValueException
    {
        SIUnit targetUnit =
                Unit.lookupOrCreateSIUnitWithSICoefficients(SICoefficients.multiply(left.getUnit().getSICoefficients(),
                        right.getUnit().getSICoefficients()).toString());
        MutableDoubleVector.Rel.Sparse<SIUnit> work =
                new MutableDoubleVector.Rel.Sparse<SIUnit>(left.deepCopyOfData(), targetUnit);
        work.scaleValueByValue(right);
        return work;
    }

    /**
     * Multiply the values in a DoubleVector and a double array value by value and store the result in a new
     * MutableDoubleVector.Abs.Dense&lt;U&gt;.
     * @param left DoubleVector.Abs.Dense&lt;U&gt;; the DoubleVector
     * @param right double[]; the double array
     * @param <U> Unit; the unit of the left parameter and the result
     * @return MutableDoubleVector.Abs.Dense&lt;U&gt;
     * @throws ValueException when the DoubleVector and the array do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Dense<U> times(final DoubleVector.Abs.Dense<U> left,
            final double[] right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Dense<U>) left.mutable().scaleValueByValue(right);
    }

    /**
     * Multiply the values in a DoubleVector and a double array value by value and store the result in a new
     * MutableDoubleVector.Abs.Sparse&lt;U&gt;.
     * @param left DoubleVector.Abs.Sparse&lt;U&gt;; the DoubleVector
     * @param right double[]; the double array
     * @param <U> Unit; the unit of the left parameter and the result
     * @return MutableDoubleVector.Abs.Sparse&lt;U&gt;
     * @throws ValueException when the DoubleVector and the array do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Sparse<U> times(final DoubleVector.Abs.Sparse<U> left,
            final double[] right) throws ValueException
    {
        return (MutableDoubleVector.Abs.Sparse<U>) left.mutable().scaleValueByValue(right);
    }

    /**
     * Multiply the values in a DoubleVector and a double array value by value and store the result in a new
     * MutableDoubleVector.Rel.Dense&lt;U&gt;.
     * @param left DoubleVector.Rel.Dense&lt;U&gt;; the DoubleVector
     * @param right double[]; the double array
     * @param <U> Unit; the unit of the left parameter and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when the DoubleVector and the array do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> times(final DoubleVector.Rel.Dense<U> left,
            final double[] right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Dense<U>) left.mutable().scaleValueByValue(right);
    }

    /**
     * Multiply the values in a DoubleVector and a double array value by value and store the result in a new
     * MutableDoubleVector.Rel.Sparse&lt;U&gt;.
     * @param left DoubleVector.Rel.Sparse&lt;U&gt;; the DoubleVector
     * @param right double[]; the double array
     * @param <U> Unit; the unit of the left parameter and the result
     * @return MutableDoubleVector.Rel.Sparse&lt;U&gt;
     * @throws ValueException when the DoubleVector and the array do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Sparse<U> times(final DoubleVector.Rel.Sparse<U> left,
            final double[] right) throws ValueException
    {
        return (MutableDoubleVector.Rel.Sparse<U>) left.mutable().scaleValueByValue(right);
    }

    /**
     * Make the Sparse equivalent of a DenseDoubleMatrix1D.
     * @param dense DoubleMatrix1D; the Dense DoubleMatrix1D
     * @return SparseDoubleMatrix1D
     */
    private static SparseDoubleMatrix1D makeSparse(final DoubleMatrix1D dense)
    {
        SparseDoubleMatrix1D result = new SparseDoubleMatrix1D((int) dense.size());
        result.assign(dense);
        return result;
    }

    /**
     * Create a Sparse version of a Dense DoubleVector.
     * @param in DoubleVector.Abs.Dense&lt;U&gt;; the Dense DoubleVector
     * @param <U> Unit; the unit of the parameter and the result
     * @return MutableDoubleVector.Abs.Sparse&lt;U&gt;
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Sparse<U> denseToSparse(final DoubleVector.Abs.Dense<U> in)
    {
        return new MutableDoubleVector.Abs.Sparse<U>(makeSparse(in.getVectorSI()), in.getUnit());
    }

    /**
     * Create a Sparse version of a Dense DoubleVector.
     * @param in DoubleVector.Rel.Dense&lt;U&gt;; the Dense DoubleVector
     * @param <U> Unit; the unit of the parameter and the result
     * @return MutableDoubleVector.Rel.Sparse&lt;U&gt;
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Sparse<U> denseToSparse(final DoubleVector.Rel.Dense<U> in)
    {
        return new MutableDoubleVector.Rel.Sparse<U>(makeSparse(in.getVectorSI()), in.getUnit());
    }

    /**
     * Make the Dense equivalent of a SparseDoubleMatrix1D.
     * @param sparse DoubleMatrix1D; the Sparse DoubleMatrix1D
     * @return DenseDoubleMatrix1D
     */
    private static DenseDoubleMatrix1D makeDense(final DoubleMatrix1D sparse)
    {
        DenseDoubleMatrix1D result = new DenseDoubleMatrix1D((int) sparse.size());
        result.assign(sparse);
        return result;
    }

    /**
     * Create a Dense version of a Sparse DoubleVector.
     * @param in DoubleVector.Abs.Sparse&lt;U&gt;; the Sparse DoubleVector
     * @param <U> Unit; the unit of the parameter and the result
     * @return MutableDoubleVector.Abs.Dense&lt;U&gt;
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Dense<U> sparseToDense(final DoubleVector.Abs.Sparse<U> in)
    {
        return new MutableDoubleVector.Abs.Dense<U>(makeDense(in.getVectorSI()), in.getUnit());
    }

    /**
     * Create a Dense version of a Sparse DoubleVector.
     * @param in DoubleVector.Rel.Sparse&lt;U&gt;; the Sparse DoubleVector
     * @param <U> Unit; the unit of the parameter and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> sparseToDense(final DoubleVector.Rel.Sparse<U> in)
    {
        return new MutableDoubleVector.Rel.Dense<U>(makeDense(in.getVectorSI()), in.getUnit());
    }

    /**
     * Interpolate between or extrapolate over two values.
     * @param zero DoubleVector.Abs.Dense&lt;U&gt;; zero reference (returned when ratio == 0)
     * @param one DoubleVector.Abs.Dense&lt;U&gt;; one reference (returned when ratio == 1)
     * @param ratio double; the ratio that determines where between (or outside) zero and one the result lies
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Dense&lt;U&gt;
     * @throws ValueException when zero and one do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Dense<U> interpolate(final DoubleVector.Abs.Dense<U> zero,
            final DoubleVector.Abs.Dense<U> one, final double ratio) throws ValueException
    {
        MutableDoubleVector.Abs.Dense<U> result = zero.mutable();
        for (int index = result.size(); --index >= 0;)
        {
            result.setSI(index, result.getSI(index) * (1 - ratio) + one.getSI(index) * ratio);
        }
        return result;
    }

    /**
     * Interpolate between or extrapolate over two values.
     * @param zero DoubleVector.Rel.Dense&lt;U&gt;; zero reference (returned when ratio == 0)
     * @param one DoubleVector.Rel.Dense&lt;U&gt;; one reference (returned when ratio == 1)
     * @param ratio double; the ratio that determines where between (or outside) zero and one the result lies
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Dense&lt;U&gt;
     * @throws ValueException when zero and one do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Dense<U> interpolate(final DoubleVector.Rel.Dense<U> zero,
            final DoubleVector.Rel.Dense<U> one, final double ratio) throws ValueException
    {
        MutableDoubleVector.Rel.Dense<U> result = zero.mutable();
        for (int index = result.size(); --index >= 0;)
        {
            result.setSI(index, result.getSI(index) * (1 - ratio) + one.getSI(index) * ratio);
        }
        return result;
    }

    /**
     * Interpolate between or extrapolate over two values.
     * @param zero DoubleVector.Abs.Sparse&lt;U&gt;; zero reference (returned when ratio == 0)
     * @param one DoubleVector.Abs.Sparse&lt;U&gt;; one reference (returned when ratio == 1)
     * @param ratio double; the ratio that determines where between (or outside) zero and one the result lies
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Abs.Sparse&lt;U&gt;
     * @throws ValueException when zero and one do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Abs.Sparse<U> interpolate(
            final DoubleVector.Abs.Sparse<U> zero, final DoubleVector.Abs.Sparse<U> one, final double ratio)
            throws ValueException
    {
        MutableDoubleVector.Abs.Sparse<U> result = zero.mutable();
        for (int index = result.size(); --index >= 0;)
        {
            result.setSI(index, result.getSI(index) * (1 - ratio) + one.getSI(index) * ratio);
        }
        return result;
    }

    /**
     * Interpolate between or extrapolate over two values.
     * @param zero DoubleVector.Rel.Sparse&lt;U&gt;; zero reference (returned when ratio == 0)
     * @param one DoubleVector.Rel.Sparse&lt;U&gt;; one reference (returned when ratio == 1)
     * @param ratio double; the ratio that determines where between (or outside) zero and one the result lies
     * @param <U> Unit; the unit of the parameters and the result
     * @return MutableDoubleVector.Rel.Sparse&lt;U&gt;
     * @throws ValueException when zero and one do not have the same size
     */
    public static <U extends Unit<U>> MutableDoubleVector.Rel.Sparse<U> interpolate(
            final DoubleVector.Rel.Sparse<U> zero, final DoubleVector.Rel.Sparse<U> one, final double ratio)
            throws ValueException
    {
        MutableDoubleVector.Rel.Sparse<U> result = zero.mutable();
        for (int index = result.size(); --index >= 0;)
        {
            result.setSI(index, result.getSI(index) * (1 - ratio) + one.getSI(index) * ratio);
        }
        return result;
    }

}