/// <inheritdoc/>
 public override RealVector ebeDivide(RealVector v)
 {
     if (v is ArrayRealVector)
     {
         double[] vData = ((ArrayRealVector)v).data;
         int      dim   = vData.Length;
         checkVectorDimensions(dim);
         ArrayRealVector result     = new ArrayRealVector(dim);
         double[]        resultData = result.data;
         for (int i = 0; i < dim; i++)
         {
             resultData[i] = data[i] / vData[i];
         }
         return(result);
     }
     else
     {
         checkVectorDimensions(v);
         double[] outp = (Double[])data.Clone();
         for (int i = 0; i < data.Length; i++)
         {
             outp[i] /= v.getEntry(i);
         }
         return(new ArrayRealVector(outp, false));
     }
 }
            /// <summary>
            /// Solves the linear equation A &times; X = B for symmetric matrices A.
            /// <para>
            /// This method only finds exact linear solutions, i.e. solutions for
            /// which ||A &times; X - B|| is exactly 0.
            /// </para>
            /// </summary>
            /// <param name="b">Right-hand side of the equation A &times; X = B.</param>
            /// <returns>Vector X that minimizes the two norm of A &times; X - B.</returns>
            /// <exception cref=DimensionMismatchException""> if the matrices dimensions do not
            /// match.</exception>
            /// <exception cref="SingularMatrixException"> if the decomposed matrix is singular.
            /// </exception>
            public RealVector solve(RealVector b)
            {
                if (!isNonSingular())
                {
                    throw new SingularMatrixException();
                }

                int m = realEigenvalues.Length;

                if (b.getDimension() != m)
                {
                    throw new DimensionMismatchException(b.getDimension(), m);
                }

                double[] bp = new double[m];
                for (int i = 0; i < m; ++i)
                {
                    ArrayRealVector v     = eigenvectors[i];
                    double[]        vData = v.getDataRef();
                    double          s     = v.dotProduct(b) / realEigenvalues[i];
                    for (int j = 0; j < m; ++j)
                    {
                        bp[j] += s * vData[j];
                    }
                }

                return(new ArrayRealVector(bp, false));
            }
 /// <inheritdoc/>
 public new ArrayRealVector subtract(RealVector v)
 {
     if (v is ArrayRealVector)
     {
         double[] vData = ((ArrayRealVector)v).data;
         int      dim   = vData.Length;
         checkVectorDimensions(dim);
         ArrayRealVector result     = new ArrayRealVector(dim);
         double[]        resultData = result.data;
         for (int i = 0; i < dim; i++)
         {
             resultData[i] = data[i] - vData[i];
         }
         return(result);
     }
     else
     {
         checkVectorDimensions(v);
         double[]            outp = (Double[])data.Clone();
         IEnumerator <Entry> it   = v.iterator();
         while (it.MoveNext())
         {
             Entry e = it.Current;
             outp[e.getIndex()] -= e.getValue();
         }
         return(new ArrayRealVector(outp, false));
     }
 }
        /// <summary>
        /// Construct a vector by appending one vector to another vector.
        /// </summary>
        /// <param name="v1">First vector (will be put in front of the new vector).</param>
        /// <param name="v2">Second vector (will be put at back of the new vector).</param>
        public ArrayRealVector(double[] v1, ArrayRealVector v2)
        {
            int l1 = v1.Length;
            int l2 = v2.getDimension();

            data = new double[l1 + l2];
            Array.Copy(v1, 0, data, 0, l1);
            Array.Copy(v2.data, 0, data, l1, l2);
        }
        /// <summary>
        /// Parse a string to produce a <see cref="RealVector"/> object.
        /// </summary>
        /// <param name="source">String to parse.</param>
        /// <returns>the parsed <see cref="RealVector"/> object.</returns>
        /// <exception cref="MathParseException"> if the beginning of the specified string
        /// cannot be parsed.</exception>
        public ArrayRealVector parse(String source)
        {
            Int32           parsePosition = 0;
            ArrayRealVector result        = parse(source, parsePosition);

            if (parsePosition == 0)
            {
                throw new MathParseException(source, parsePosition, typeof(ArrayRealVector));
            }
            return(result);
        }
        /// <summary>
        /// Construct a vector by appending one vector to another vector.
        /// </summary>
        /// <param name="v1">First vector (will be put in front of the new vector).</param>
        /// <param name="v2">Second vector (will be put at back of the new vector).</param>
        public ArrayRealVector(RealVector v1, ArrayRealVector v2)
        {
            int l1 = v1.getDimension();
            int l2 = v2.data.Length;

            data = new double[l1 + l2];
            for (int i = 0; i < l1; ++i)
            {
                data[i] = v1.getEntry(i);
            }
            Array.Copy(v2.data, 0, data, l1, l2);
        }
        /// <summary>
        /// Construct a vector by appending one vector to another vector.
        /// </summary>
        /// <param name="v1">First vector (will be put in front of the new vector).</param>
        /// <param name="v2">Second vector (will be put at back of the new vector).</param>
        public ArrayRealVector(ArrayRealVector v1, RealVector v2)
        {
            int l1 = v1.data.Length;
            int l2 = v2.getDimension();

            data = new double[l1 + l2];
            Array.Copy(v1.data, 0, data, 0, l1);
            for (int i = 0; i < l2; ++i)
            {
                data[l1 + i] = v2.getEntry(i);
            }
        }
            /// <inheritdoc/>
            public RealMatrix solve(RealMatrix b)
            {
                if (!isNonSingular())
                {
                    throw new SingularMatrixException();
                }

                int m = realEigenvalues.Length;

                if (b.getRowDimension() != m)
                {
                    throw new DimensionMismatchException(b.getRowDimension(), m);
                }

                int nColB = b.getColumnDimension();

                double[][] bp     = new double[m][];
                double[]   tmpCol = new double[m];
                for (int k = 0; k < nColB; ++k)
                {
                    for (int i = 0; i < m; ++i)
                    {
                        tmpCol[i] = b.getEntry(i, k);
                        bp[i][k]  = 0;
                    }
                    for (int i = 0; i < m; ++i)
                    {
                        ArrayRealVector v     = eigenvectors[i];
                        double[]        vData = v.getDataRef();
                        double          s     = 0;
                        for (int j = 0; j < m; ++j)
                        {
                            s += v.getEntry(j) * tmpCol[j];
                        }
                        s /= realEigenvalues[i];
                        for (int j = 0; j < m; ++j)
                        {
                            bp[j][k] += s * vData[j];
                        }
                    }
                }

                return(new Array2DRowRealMatrix(bp, false));
            }
        /// <inheritdoc/>
        public override RealVector getSubVector(int index, int n)
        {
            if (n < 0)
            {
                throw new NotPositiveException <Int32>(new LocalizedFormats("NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE"), n);
            }
            ArrayRealVector outp = new ArrayRealVector(n);

            try
            {
                Array.Copy(data, index, outp.data, 0, n);
            }
            catch (IndexOutOfRangeException)
            {
                checkIndex(index);
                checkIndex(index + n - 1);
            }
            return(outp);
        }
 /// <summary>
 /// Construct a vector by appending a vector to this vector.
 /// </summary>
 /// <param name="v">Vector to append to this one.</param>
 /// <returns>a new vector.</returns>
 public ArrayRealVector append(ArrayRealVector v)
 {
     return(new ArrayRealVector(this, v));
 }
 /// <summary>
 /// Construct a vector by appending one vector to another vector.
 /// </summary>
 /// <param name="v1">First vector (will be put in front of the new vector).</param>
 /// <param name="v2">Second vector (will be put at back of the new vector).</param>
 public ArrayRealVector(ArrayRealVector v1, ArrayRealVector v2)
 {
     data = new double[v1.data.Length + v2.data.Length];
     Array.Copy(v1.data, 0, data, 0, v1.data.Length);
     Array.Copy(v2.data, 0, data, v1.data.Length, v2.data.Length);
 }
 /// <summary>
 /// Construct a vector from another vector.
 /// </summary>
 /// <param name="v">Vector to copy.</param>
 /// <param name="deep">If <c>true</c> perform a deep copy, otherwise perform a
 /// shallow copy.</param>
 public ArrayRealVector(ArrayRealVector v, Boolean deep)
 {
     data = deep ? (Double[])v.data.Clone() : v.data;
 }
 /// <summary>
 /// Construct a vector from another vector, using a deep copy.
 /// </summary>
 /// <param name="v">Vector to copy.</param>
 /// <exception cref="NullArgumentException"> if <c>v</c> is <c>null</c>.</exception>
 public ArrayRealVector(ArrayRealVector v) : this(v, true)
 {
 }
        /// <summary>
        /// Find eigenvectors from a matrix transformed to Schur form.
        /// </summary>
        /// <param name="schur">the schur transformation of the matrix</param>
        /// <exception cref="MathArithmeticException"> if the Schur form has a norm of zero
        /// </exception>
        private void findEigenVectorsFromSchur(SchurTransformer schur)
        {
            double[][] matrixT = schur.getT().getData();
            double[][] matrixP = schur.getP().getData();

            int n = matrixT.Length;

            // compute matrix norm
            double norm = 0.0;

            for (int i = 0; i < n; i++)
            {
                for (int j = FastMath.max(i - 1, 0); j < n; j++)
                {
                    norm += FastMath.abs(matrixT[i][j]);
                }
            }

            // we can not handle a matrix with zero norm
            if (Precision.equals(norm, 0.0, EPSILON))
            {
                throw new MathArithmeticException(new LocalizedFormats("ZERO_NORM"));
            }

            // Backsubstitute to find vectors of upper triangular form

            double r = 0.0;
            double s = 0.0;
            double z = 0.0;

            for (int idx = n - 1; idx >= 0; idx--)
            {
                double p = realEigenvalues[idx];
                double q = imagEigenvalues[idx];

                if (Precision.equals(q, 0.0))
                {
                    // Real vector
                    int l = idx;
                    matrixT[idx][idx] = 1.0;
                    for (int i = idx - 1; i >= 0; i--)
                    {
                        double w = matrixT[i][i] - p;
                        r = 0.0;
                        for (int j = l; j <= idx; j++)
                        {
                            r += matrixT[i][j] * matrixT[j][idx];
                        }
                        if (Precision.compareTo(imagEigenvalues[i], 0.0, EPSILON) < 0)
                        {
                            z = w;
                            s = r;
                        }
                        else
                        {
                            l = i;
                            if (Precision.equals(imagEigenvalues[i], 0.0))
                            {
                                if (w != 0.0)
                                {
                                    matrixT[i][idx] = -r / w;
                                }
                                else
                                {
                                    matrixT[i][idx] = -r / (Precision.EPSILON * norm);
                                }
                            }
                            else
                            {
                                // Solve real equations
                                double x = matrixT[i][i + 1];
                                double y = matrixT[i + 1][i];
                                q = (realEigenvalues[i] - p) * (realEigenvalues[i] - p) +
                                    imagEigenvalues[i] * imagEigenvalues[i];
                                double t = (x * s - z * r) / q;
                                matrixT[i][idx] = t;
                                if (FastMath.abs(x) > FastMath.abs(z))
                                {
                                    matrixT[i + 1][idx] = (-r - w * t) / x;
                                }
                                else
                                {
                                    matrixT[i + 1][idx] = (-s - y * t) / z;
                                }
                            }

                            // Overflow control
                            double tt = FastMath.abs(matrixT[i][idx]);
                            if ((Precision.EPSILON * tt) * tt > 1)
                            {
                                for (int j = i; j <= idx; j++)
                                {
                                    matrixT[j][idx] /= tt;
                                }
                            }
                        }
                    }
                }
                else if (q < 0.0)
                {
                    // Complex vector
                    int l = idx - 1;

                    // Last vector component imaginary so matrix is triangular
                    if (FastMath.abs(matrixT[idx][idx - 1]) > FastMath.abs(matrixT[idx - 1][idx]))
                    {
                        matrixT[idx - 1][idx - 1] = q / matrixT[idx][idx - 1];
                        matrixT[idx - 1][idx]     = -(matrixT[idx][idx] - p) / matrixT[idx][idx - 1];
                    }
                    else
                    {
                        Complex result = cdiv(0.0, -matrixT[idx - 1][idx],
                                              matrixT[idx - 1][idx - 1] - p, q);
                        matrixT[idx - 1][idx - 1] = result.getReal();
                        matrixT[idx - 1][idx]     = result.getImaginary();
                    }

                    matrixT[idx][idx - 1] = 0.0;
                    matrixT[idx][idx]     = 1.0;

                    for (int i = idx - 2; i >= 0; i--)
                    {
                        double ra = 0.0;
                        double sa = 0.0;
                        for (int j = l; j <= idx; j++)
                        {
                            ra += matrixT[i][j] * matrixT[j][idx - 1];
                            sa += matrixT[i][j] * matrixT[j][idx];
                        }
                        double w = matrixT[i][i] - p;

                        if (Precision.compareTo(imagEigenvalues[i], 0.0, EPSILON) < 0)
                        {
                            z = w;
                            r = ra;
                            s = sa;
                        }
                        else
                        {
                            l = i;
                            if (Precision.equals(imagEigenvalues[i], 0.0))
                            {
                                Complex c = cdiv(-ra, -sa, w, q);
                                matrixT[i][idx - 1] = c.getReal();
                                matrixT[i][idx]     = c.getImaginary();
                            }
                            else
                            {
                                // Solve complex equations
                                double x  = matrixT[i][i + 1];
                                double y  = matrixT[i + 1][i];
                                double vr = (realEigenvalues[i] - p) * (realEigenvalues[i] - p) +
                                            imagEigenvalues[i] * imagEigenvalues[i] - q * q;
                                double vi = (realEigenvalues[i] - p) * 2.0 * q;
                                if (Precision.equals(vr, 0.0) && Precision.equals(vi, 0.0))
                                {
                                    vr = Precision.EPSILON * norm *
                                         (FastMath.abs(w) + FastMath.abs(q) + FastMath.abs(x) +
                                          FastMath.abs(y) + FastMath.abs(z));
                                }
                                Complex c = cdiv(x * r - z * ra + q * sa,
                                                 x * s - z * sa - q * ra, vr, vi);
                                matrixT[i][idx - 1] = c.getReal();
                                matrixT[i][idx]     = c.getImaginary();

                                if (FastMath.abs(x) > (FastMath.abs(z) + FastMath.abs(q)))
                                {
                                    matrixT[i + 1][idx - 1] = (-ra - w * matrixT[i][idx - 1] +
                                                               q * matrixT[i][idx]) / x;
                                    matrixT[i + 1][idx] = (-sa - w * matrixT[i][idx] -
                                                           q * matrixT[i][idx - 1]) / x;
                                }
                                else
                                {
                                    Complex c2 = cdiv(-r - y * matrixT[i][idx - 1],
                                                      -s - y * matrixT[i][idx], z, q);
                                    matrixT[i + 1][idx - 1] = c2.getReal();
                                    matrixT[i + 1][idx]     = c2.getImaginary();
                                }
                            }

                            // Overflow control
                            double t = FastMath.max(FastMath.abs(matrixT[i][idx - 1]),
                                                    FastMath.abs(matrixT[i][idx]));
                            if ((Precision.EPSILON * t) * t > 1)
                            {
                                for (int j = i; j <= idx; j++)
                                {
                                    matrixT[j][idx - 1] /= t;
                                    matrixT[j][idx]     /= t;
                                }
                            }
                        }
                    }
                }
            }

            // Back transformation to get eigenvectors of original matrix
            for (int j = n - 1; j >= 0; j--)
            {
                for (int i = 0; i <= n - 1; i++)
                {
                    z = 0.0;
                    for (int k = 0; k <= FastMath.min(j, n - 1); k++)
                    {
                        z += matrixP[i][k] * matrixT[k][j];
                    }
                    matrixP[i][j] = z;
                }
            }

            eigenvectors = new ArrayRealVector[n];
            double[] tmp = new double[n];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    tmp[j] = matrixP[j][i];
                }
                eigenvectors[i] = new ArrayRealVector(tmp);
            }
        }
        /// <summary>
        /// Find eigenvalues and eigenvectors (Dubrulle et al., 1971)
        /// </summary>
        /// <param name="householderMatrix">Householder matrix of the transformation
        /// to tridiagonal form.</param>
        private void findEigenVectors(double[][] householderMatrix)
        {
            double[][] z = (Double[][])householderMatrix.Clone();
            int        n = main.Length;

            realEigenvalues = new double[n];
            imagEigenvalues = new double[n];
            double[] e = new double[n];
            for (int i = 0; i < n - 1; i++)
            {
                realEigenvalues[i] = main[i];
                e[i] = secondary[i];
            }
            realEigenvalues[n - 1] = main[n - 1];
            e[n - 1] = 0;

            // Determine the largest main and secondary value in absolute term.
            double maxAbsoluteValue = 0;

            for (int i = 0; i < n; i++)
            {
                if (FastMath.abs(realEigenvalues[i]) > maxAbsoluteValue)
                {
                    maxAbsoluteValue = FastMath.abs(realEigenvalues[i]);
                }
                if (FastMath.abs(e[i]) > maxAbsoluteValue)
                {
                    maxAbsoluteValue = FastMath.abs(e[i]);
                }
            }
            // Make null any main and secondary value too small to be significant
            if (maxAbsoluteValue != 0)
            {
                for (int i = 0; i < n; i++)
                {
                    if (FastMath.abs(realEigenvalues[i]) <= Precision.EPSILON * maxAbsoluteValue)
                    {
                        realEigenvalues[i] = 0;
                    }
                    if (FastMath.abs(e[i]) <= Precision.EPSILON * maxAbsoluteValue)
                    {
                        e[i] = 0;
                    }
                }
            }

            for (int j = 0; j < n; j++)
            {
                int its = 0;
                int m;
                do
                {
                    for (m = j; m < n - 1; m++)
                    {
                        double delta = FastMath.abs(realEigenvalues[m]) +
                                       FastMath.abs(realEigenvalues[m + 1]);
                        if (FastMath.abs(e[m]) + delta == delta)
                        {
                            break;
                        }
                    }
                    if (m != j)
                    {
                        if (its == maxIter)
                        {
                            throw new MaxCountExceededException <Byte>(new LocalizedFormats("CONVERGENCE_FAILED"), maxIter);
                        }
                        its++;
                        double q = (realEigenvalues[j + 1] - realEigenvalues[j]) / (2 * e[j]);
                        double t = FastMath.sqrt(1 + q * q);
                        if (q < 0.0)
                        {
                            q = realEigenvalues[m] - realEigenvalues[j] + e[j] / (q - t);
                        }
                        else
                        {
                            q = realEigenvalues[m] - realEigenvalues[j] + e[j] / (q + t);
                        }
                        double u = 0.0;
                        double s = 1.0;
                        double c = 1.0;
                        int    i;
                        for (i = m - 1; i >= j; i--)
                        {
                            double p = s * e[i];
                            double h = c * e[i];
                            if (FastMath.abs(p) >= FastMath.abs(q))
                            {
                                c        = q / p;
                                t        = FastMath.sqrt(c * c + 1.0);
                                e[i + 1] = p * t;
                                s        = 1.0 / t;
                                c       *= s;
                            }
                            else
                            {
                                s        = p / q;
                                t        = FastMath.sqrt(s * s + 1.0);
                                e[i + 1] = q * t;
                                c        = 1.0 / t;
                                s       *= c;
                            }
                            if (e[i + 1] == 0.0)
                            {
                                realEigenvalues[i + 1] -= u;
                                e[m] = 0.0;
                                break;
                            }
                            q = realEigenvalues[i + 1] - u;
                            t = (realEigenvalues[i] - q) * s + 2.0 * c * h;
                            u = s * t;
                            realEigenvalues[i + 1] = q + u;
                            q = c * t - h;
                            for (int ia = 0; ia < n; ia++)
                            {
                                p            = z[ia][i + 1];
                                z[ia][i + 1] = s * z[ia][i] + c * p;
                                z[ia][i]     = c * z[ia][i] - s * p;
                            }
                        }
                        if (t == 0.0 && i >= j)
                        {
                            continue;
                        }
                        realEigenvalues[j] -= u;
                        e[j] = q;
                        e[m] = 0.0;
                    }
                } while (m != j);
            }

            //Sort the eigen values (and vectors) in increase order
            for (int i = 0; i < n; i++)
            {
                int    k = i;
                double p = realEigenvalues[i];
                for (int j = i + 1; j < n; j++)
                {
                    if (realEigenvalues[j] > p)
                    {
                        k = j;
                        p = realEigenvalues[j];
                    }
                }
                if (k != i)
                {
                    realEigenvalues[k] = realEigenvalues[i];
                    realEigenvalues[i] = p;
                    for (int j = 0; j < n; j++)
                    {
                        p       = z[j][i];
                        z[j][i] = z[j][k];
                        z[j][k] = p;
                    }
                }
            }

            // Determine the largest eigen value in absolute term.
            maxAbsoluteValue = 0;
            for (int i = 0; i < n; i++)
            {
                if (FastMath.abs(realEigenvalues[i]) > maxAbsoluteValue)
                {
                    maxAbsoluteValue = FastMath.abs(realEigenvalues[i]);
                }
            }
            // Make null any eigen value too small to be significant
            if (maxAbsoluteValue != 0.0)
            {
                for (int i = 0; i < n; i++)
                {
                    if (FastMath.abs(realEigenvalues[i]) < Precision.EPSILON * maxAbsoluteValue)
                    {
                        realEigenvalues[i] = 0;
                    }
                }
            }
            eigenvectors = new ArrayRealVector[n];
            double[] tmp = new double[n];
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    tmp[j] = z[j][i];
                }
                eigenvectors[i] = new ArrayRealVector(tmp);
            }
        }